/* * drivers/arisc/interfaces/arisc_rsb.c * * Copyright (c) 2013 Allwinner. * 2013-07-01 Written by superm (superm@allwinnertech.com). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include "../arisc_i.h" /** * twi read block data. * @cfg: point of arisc_twi_block_cfg struct; * * return: result, 0 - read register successed, * !0 - read register failed or the len more then max len; */ int arisc_twi_read_block_data(struct arisc_twi_block_cfg *cfg) { int i; int result; volatile u32 paras[22]; if ((cfg == NULL) || (cfg->addr == NULL) || (cfg->data == NULL) || (cfg->len > TWI_TRANS_BYTE_MAX) || ((cfg->msgattr != ARISC_MESSAGE_ATTR_HARDSYN) && (cfg->msgattr != ARISC_MESSAGE_ATTR_SOFTSYN))) { ARISC_WRN("twi read reg paras error\n"); return -EINVAL; } /* * package address and data to message->paras, * message->paras data layout: * |para[0]|para[1]|para[2]|para[3]|para[4]| * |len |addr0~3|addr4~7|data0~3|data4~7| */ memset((void *)paras, 0, sizeof(paras[0]) * 22); paras[0] = cfg->len; for (i = 0; i < cfg->len; i++) { if (i < 4) /* pack 8bit addr0~addr3 into 32bit paras[0] */ paras[1] |= (cfg->addr[i] << (i * 8)); else /* pack 8bit addr4~addr7 into 32bit paras[1] */ paras[2] |= (cfg->addr[i] << ((i - 4) * 8)); } /* send message use hwmsgbox */ result = invoke_scp_fn_smc(ARM_SVC_ARISC_TWI_READ_BLOCK_DATA, virt_to_phys(paras), 0, 0); /* copy message readout data to user data buffer */ for (i = 0; i < cfg->len; i++) { if (i < 4) cfg->data[i] = ((paras[3]) >> (i * 8)) & 0xff; else cfg->data[i] = ((paras[4]) >> ((i - 4) * 8)) & 0xff; } return result; } EXPORT_SYMBOL(arisc_twi_read_block_data); /** * twi write block data. * @cfg: point of arisc_twi_block_cfg struct; * * return: result, 0 - write register successed, * !0 - write register failedor the len more then max len; */ int arisc_twi_write_block_data(struct arisc_twi_block_cfg *cfg) { int i; int result; volatile u32 paras[22]; if ((cfg == NULL) || (cfg->addr == NULL) || (cfg->data == NULL) || (cfg->len > TWI_TRANS_BYTE_MAX) || ((cfg->msgattr != ARISC_MESSAGE_ATTR_HARDSYN) && (cfg->msgattr != ARISC_MESSAGE_ATTR_SOFTSYN))) { ARISC_WRN("twi write reg paras error\n"); return -EINVAL; } /* * package address and data to message->paras, * message->paras data layout: * |para[0]|para[1]|para[2]|para[3]|para[4]| * |len |addr0~3|addr4~7|data0~3|data4~7| */ memset((void *)paras, 0, sizeof(paras[0]) * 22); paras[0] = cfg->len; for (i = 0; i < cfg->len; i++) { if (i < 4) { /* pack 8bit addr0~addr3 into 32bit paras[0] */ paras[1] |= (cfg->addr[i] << (i * 8)); /* pack 8bit data0~data3 into 32bit paras[2] */ paras[3] |= (cfg->data[i] << (i * 8)); } else { /* pack 8bit addr4~addr7 into 32bit paras[1] */ paras[2] |= (cfg->addr[i] << ((i - 4) * 8)); /* pack 8bit data4~data7 into 32bit paras[3] */ paras[4] |= (cfg->data[i] << ((i - 4) * 8)); } } /* send message use hwmsgbox */ result = invoke_scp_fn_smc(ARM_SVC_ARISC_TWI_WRITE_BLOCK_DATA, virt_to_phys(paras), 0, 0); return result; } EXPORT_SYMBOL(arisc_twi_write_block_data); /** * twi bits operation sync. * @cfg: point of arisc_twi_bits_cfg struct; * * return: result, 0 - bits operation successed, * !0 - bits operation failed, or the len more then max len; * * twi clear bits internal: * data = twi_read(addr); * data = data & (~mask); * twi_write(addr, data); * * twi set bits internal: * data = twi_read(addr); * data = data | mask; * twi_write(addr, data); * */ int twi_bits_ops_sync(struct arisc_twi_bits_cfg *cfg) { int i; int result; volatile u32 paras[22]; if ((cfg == NULL) || (cfg->addr == NULL) || (cfg->mask == NULL) || (cfg->delay == NULL) || (cfg->len > TWI_TRANS_BYTE_MAX) || ((cfg->msgattr != ARISC_MESSAGE_ATTR_HARDSYN) && (cfg->msgattr != ARISC_MESSAGE_ATTR_SOFTSYN))) { ARISC_WRN("twi clear bits sync paras error\n"); return -EINVAL; } /* * package address and data to message->paras, * message->paras data layout: * |para[0]|para[1]|para[2]|para[3]|para[4]|para[5] |para[6] |para[7]| * |len |addr0~3|addr4~7|mask0~3|mask4~7|delay0~3|delay4~7|ops | */ memset((void *)paras, 0, sizeof(paras[0]) * 22); paras[0] = cfg->len; paras[7] = cfg->ops; for (i = 0; i < cfg->len; i++) { if (i < 4) { /* pack 8bit addr0~addr3 into 32bit paras[0] */ paras[1] |= (cfg->addr[i] << (i * 8)); /* pack 8bit mask0~mask3 into 32bit paras[2] */ paras[3] |= (cfg->mask[i] << (i * 8)); /* pack 8bit delay0~delay3 into 32bit paras[3] */ paras[5] |= (cfg->delay[i] << (i * 8)); } else { /* pack 8bit addr4~addr7 into 32bit paras[1] */ paras[2] |= (cfg->addr[i] << ((i - 4) * 8)); /* pack 8bit mask4~mask7 into 32bit paras[3] */ paras[4] |= (cfg->mask[i] << ((i - 4) * 8)); /* pack 8bit delay4~delay7 into 32bit paras[5] */ paras[6] |= (cfg->delay[i] << ((i - 4) * 8)); } } /* send message use hwmsgbox */ result = invoke_scp_fn_smc(ARM_SVC_ARISC_TWI_BITS_OPS_SYNC, virt_to_phys(paras), 0, 0); return result; } EXPORT_SYMBOL(twi_bits_ops_sync);