static int smsi2c_ts_enable(void *context) { #define TS_CLK 4000000 //6000000 //#define TS_CONTROL_ENABLE struct SmsTsEnable_S TsEnableMsg = {{MSG_SMS_ENBALE_TS_INTERFACE_REQ, 0, 11, sizeof(struct SmsTsEnable_S), 0}, TS_CLK,//24000000, TSI_PARALLEL_ON_HIF, //TSI_PARALLEL_ON_HIF, TSI_SERIAL_ON_SDIO, //wood, ++--, @20140917 TSI_SIGNALS_ACTIVE_HIGH,//TSI_SIGNALS_ACTIVE_LOW, 0,//0, TSI_SIG_OUT_FALL_EDGE, TSI_BIT7_IS_MSB, #ifdef TS_CONTROL_ENABLE 1, #else 0, #endif TSI_TRANSPARENT,//TSI_ENCAPSULATED, 21};//21 struct smsi2c_device *smsdev = (struct smsi2c_device *)context; if (!smsdev) { sms_err("smsi2c_ts_enable smsdev NULL!!\n"); return -ENODEV; } return smsi2c_sendrequest(context, &TsEnableMsg, sizeof(TsEnableMsg)); //return i2c_master_normal_send(smsdev->client, &TsEnableMsg, sizeof(TsEnableMsg), I2C_SCL_TATE); //using 400KHz clk }
// allocate and init i2c dev descriptor // update i2c client params // static int smsi2c_probe(void) { int ret; struct smsi2c_device *smsdev; struct smsdevice_params_t params; struct SmsMsgHdr_S smsmsg; struct SmsMsgData2Args_S setIntMsg = {{MSG_SMS_SPI_INT_LINE_SET_REQ, 0, 11, sizeof(struct SmsMsgData2Args_S), 0}, {0xff, 20}}; struct i2c_board_info smsi2c_info = { I2C_BOARD_INFO("smsi2c", sms_i2c_addr), }; smsdev = kzalloc(sizeof(struct smsi2c_device), GFP_KERNEL); if (!smsdev) { sms_err("Cannot allocate memory for I2C device driver.\n"); return -ENOMEM; } g_smsi2c_device = smsdev; sms_debug ("Memory allocated"); smsdev->adap = i2c_get_adapter(host_i2c_ctrl); if (!smsdev->adap) { sms_err("Cannot get adapter #%d.\n", host_i2c_ctrl); ret = -ENODEV; goto failed_allocate_adapter; } sms_debug ("Got the adapter"); smsi2c_info.platform_data = smsdev; smsdev->client = i2c_new_device(smsdev->adap, &smsi2c_info); if (!smsdev->client) { sms_err("Cannot register I2C device with addr 0x%x.\n", sms_i2c_addr); ret = -ENODEV; goto failed_allocate_device; } sms_debug ("Got the device"); ret = gpio_request(host_i2c_intr_pin, "sms_gpio"); if (ret) { sms_err("failed to get sms_gpio\n"); goto failed_allocate_gpio; } gpio_direction_input(host_i2c_intr_pin); gpio_export(host_i2c_intr_pin, 0); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) irq_set_irq_type(gpio_to_irq(host_i2c_intr_pin), IRQ_TYPE_EDGE_FALLING); #else set_irq_type(gpio_to_irq(host_i2c_intr_pin), IRQ_TYPE_EDGE_FALLING); #endif /*register irq*/ ret = request_irq( gpio_to_irq(host_i2c_intr_pin), (irq_handler_t)smsi2c_interrupt, IRQF_TRIGGER_RISING, "SMSI2C", smsdev); if (ret < 0) { sms_err("failed to allocate interrupt for SMS\n"); ret = -ENODEV; goto failed_allocate_interrupt; } if (device_int_line != 0xFFFFFFFF) { /* Device is not using the default interrupt pin*/ sms_debug("Device is not using the default int pin, need to set the interrupt pin to %d", device_int_line); setIntMsg.msgData[1] = device_int_line; ret = smsi2c_sendrequest(smsdev, &setIntMsg, sizeof(setIntMsg)); msleep(50); } init_completion(&smsdev->version_ex_done); smsdev->wait_for_version_resp = 1; SMS_INIT_MSG(&smsmsg, MSG_SMS_GET_VERSION_EX_REQ, sizeof(struct SmsMsgHdr_S)); smsi2c_sendrequest(smsdev, &smsmsg, sizeof(smsmsg)); /*Wait for response*/ ret = wait_for_completion_timeout(&smsdev->version_ex_done, msecs_to_jiffies(500)); if (ret > 0) { /*Got version. device is in*/ sms_debug("Found and identified the I2C device"); } else { /* No response recieved*/ sms_err("No response to get version command"); ret = -ETIME; goto failed_registering_coredev; } memset(¶ms, 0, sizeof(struct smsdevice_params_t)); params.device = (struct device *)&smsdev->client->adapter->dev; #ifdef SMS_RK_TS params.buffer_size = MAX_I2C_BUF_SIZE; params.num_buffers = MAX_I2C_BUF_NUMBER; params.require_node_buffer = 1; #else params.buffer_size = 0x400; params.num_buffers = 20; #endif params.context = smsdev; snprintf(params.devpath, sizeof(params.devpath), "i2c\\%s", "smsi2c"); params.sendrequest_handler = smsi2c_sendrequest; params.loadfirmware_handler = smsi2c_loadfirmware_handler; switch(smsdev->chip_model) { case 0: params.device_type = 0; break; case 0x1002: case 0x1102: case 0x1004: params.device_type = SMS_NOVA_B0; break; case 0x1182: params.device_type = SMS_VENICE; break; case 0x1530: params.device_type = SMS_DENVER_1530; break; case 0x2130: params.device_type = SMS_PELE; break; case 0x2160: params.device_type = SMS_DENVER_2160; break; case 0x2180: params.device_type = SMS_MING; break; case 0x2230: params.device_type = SMS_RIO; break; case 0x3130: params.device_type = SMS_ZICO; break; case 0x3180: params.device_type = SMS_QING; break; case 0x3230: params.device_type = SMS_SANTOS; break; case 0x4470: if (smsdev->chip_metal >= 2) params.device_type = SMS_SIENA_A2; else params.device_type = SMS_SIENA; break; default: params.device_type = 0; break; } /* Use SMS_DEVICE_FAMILY2 for firmware download over SMS MSGs SMS_DEVICE_FAMILY1 for backdoor I2C firmware download */ params.flags |= SMS_DEVICE_FAMILY2; /* Device protocol completion events */ ret = smscore_register_device(¶ms, &smsdev->coredev); if (ret < 0) { printk(KERN_INFO "smscore_register_device error\n"); goto failed_registering_coredev; } ret = smscore_start_device(smsdev->coredev); if (ret < 0) { printk(KERN_INFO "smscore_start_device error\n"); goto failed_device_start; } return 0; failed_device_start: smscore_unregister_device(smsdev->coredev); failed_registering_coredev: free_irq(gpio_to_irq(host_i2c_intr_pin), smsdev); failed_allocate_interrupt: gpio_free(host_i2c_intr_pin); failed_allocate_gpio: i2c_unregister_device(smsdev->client); failed_allocate_device: i2c_put_adapter(smsdev->adap); failed_allocate_adapter: g_smsi2c_device = NULL; kfree(smsdev); return ret; }
static int smsi2c_loadfirmware_handler(void *context, void* p_data, u32 fw_size) { int ret; u8* fw_data = (u8*)p_data + 12; u32* fw_hdr = p_data; u32 actual_crc, dummy_crc,i; u32 chunk_size; u32 dummy_hdr[3]; u32 fw_addr, fw_len, dnl_offset; struct smsi2c_device *smsdev = (struct smsi2c_device *)context; u16 flags_bak = smsdev->client->flags; struct SmsMsgHdr_S BackdoorMsg = { MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ, 0, HIF_TASK, sizeof(struct SmsMsgHdr_S), 0}; fw_addr = fw_hdr[2]; fw_len = fw_hdr[1]; /*The full CRC is for debug and printing, the function doesnt use this*/ sms_debug("crc=0x%x, len=0x%x, addr=0x%x", fw_hdr[0], fw_len, fw_addr); actual_crc=0; for (i = 0; i < fw_len+8 ; i++) { actual_crc ^= ((u8*)p_data)[4+i]; } sms_debug("actual calculated crc=0x%x", actual_crc); sms_debug("Sending the firmware content in chunks of no more than %dKB.\n", MAX_CHUNK_SIZE/1024); dnl_offset = fw_addr + fw_len; smsdev->client->flags |= I2C_M_IGNORE_NAK; while (fw_len) { sms_debug("Sending backdoor command.\n"); ret = smsi2c_sendrequest(context, &BackdoorMsg, sizeof(BackdoorMsg)); if (ret < 0) { sms_err ("failed sending backdoor command"); return ret; } msleep(30); chunk_size = min((int)fw_len, MAX_CHUNK_SIZE); dnl_offset -= chunk_size; fw_len -= chunk_size; dummy_hdr[1] = chunk_size; dummy_hdr[2] = dnl_offset; dummy_crc=0; for (i = 0; i < 8 ; i++) { dummy_crc ^= ((u8*)dummy_hdr)[4+i]; } for (i = 0; i < chunk_size ; i++) { dummy_crc ^= ((u8*)(fw_data+fw_len))[i]; } sms_debug("download chunk size %d at offset 0x%x, act crc is 0x%x.\n", chunk_size, dnl_offset, dummy_crc); if (dnl_offset == fw_addr) { /* Only for the last chunk send the correct CRC*/ dummy_hdr[0] = dummy_crc; } else {/* for all but last chunk, make sure crc is wrong*/ dummy_hdr[0] = dummy_crc^0x55; } /*send header of current chunk*/ ret = smsi2c_sendrequest(context, (u8*)dummy_hdr, 12); if (ret < 0) { sms_err ("failed sending fw header"); return ret; } msleep(20); /*send the data of current chunk*/ ret = smsi2c_sendrequest(context, (u8*)(fw_data+fw_len), chunk_size); if (ret < 0) { sms_err ("failed sending fw data"); return ret; } msleep(30); } sms_debug("FW download complete.\n"); smsdev->client->flags = flags_bak; //msleep(400); smsi2c_ts_enable(context); return 0; }
static int smsi2c_loadfirmware_handler(void *context, void* p_data, u32 fw_size) { int ret; u8* fw_buf = (u8*)p_data; struct SmsMsgHdr_S BackdoorMsg = { MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ, 0, HIF_TASK, sizeof(struct SmsMsgHdr_S), 0}; struct SmsTsEnable_S TsEnableMsg = {{MSG_SMS_ENBALE_TS_INTERFACE_REQ, 0, 11, sizeof(struct SmsTsEnable_S), 0}, 15000000, TSI_SERIAL_ON_SDIO, TSI_SIGNALS_ACTIVE_LOW, 0, TSI_SIG_OUT_FALL_EDGE, TSI_BIT0_IS_MSB, 0, TSI_ENCAPSULATED, 21}; u32 sizeToCalc; u8* ptr; u32 checkSum; u32 i; u32* pFirstHeader = (u32*)fw_buf; u32 SecondHeader[3]; if (fw_size > 60*1024) { /* Send last part */ SecondHeader[0] = 0xffffffff; /* Impossible checksum */ SecondHeader[1] = pFirstHeader[1] - 2*MAX_CHUNK_SIZE; /* Length of second chunk */ SecondHeader[2] = pFirstHeader[2] + 2*MAX_CHUNK_SIZE; /* Address of second chunk */ ret = smsi2c_sendrequest(context, &BackdoorMsg, sizeof(BackdoorMsg)); msleep(50); ret = smsi2c_sendrequest(context, (u8*)(SecondHeader), 12); msleep(50); ret = smsi2c_sendrequest(context, (u8*)(fw_buf+12+2*MAX_CHUNK_SIZE), pFirstHeader[1] - 2*MAX_CHUNK_SIZE); msleep(50); /* Send middle part */ SecondHeader[0] = 0xffffffff; SecondHeader[1] = MAX_CHUNK_SIZE; SecondHeader[2] = pFirstHeader[2] + MAX_CHUNK_SIZE; ret = smsi2c_sendrequest(context, &BackdoorMsg, sizeof(BackdoorMsg)); msleep(50); ret = smsi2c_sendrequest(context, (u8*)(SecondHeader), 12); msleep(50); ret = smsi2c_sendrequest(context, (u8*)(fw_buf+12+MAX_CHUNK_SIZE), MAX_CHUNK_SIZE); msleep(50); /* Send first part Fix checksum */ pFirstHeader[1] = MAX_CHUNK_SIZE; sizeToCalc = pFirstHeader[1] + 8; ptr = fw_buf + 4; checkSum = 0; for (i = 0; i < sizeToCalc; i++) { checkSum ^= *(ptr + i); } pFirstHeader[0] = checkSum; ret = smsi2c_sendrequest(context, &BackdoorMsg, sizeof(BackdoorMsg)); msleep(50); ret = smsi2c_sendrequest(context, (u8*)(pFirstHeader), 12); msleep(50); ret = smsi2c_sendrequest(context, (u8*)(fw_buf+12), MAX_CHUNK_SIZE); } else { ret = smsi2c_sendrequest(context, (u8*)(fw_buf), 12); msleep(20); ret = smsi2c_sendrequest(context, (u8*)(fw_buf+12), fw_size-12); } msleep(20); ret = smsi2c_sendrequest(context, &TsEnableMsg, sizeof(TsEnableMsg)); return 0; }