--- /dev/null
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <mach/mt_pm_ldo.h>
+#include <mt_i2c.h>
+
+static char data_buffer[256 * 4];
+
+static ssize_t show_config(struct device *dev, struct device_attribute *attr, char *buff)
+{
+ int len = strlen(data_buffer);
+ memcpy(buff,data_buffer,len);
+ printk("Return Value:%s\n",data_buffer);
+ return len;
+}
+
+static int pows(int x, int y)
+{
+ int result = 1;
+ while (y--) result *=x;
+ return result;
+}
+
+int string2hex(const char * buffer, int cnt){
+ int c = 0;
+ char t = 0;
+ int count = cnt;
+ while (count--){
+ t = *(buffer + cnt - count - 1);
+ if ( t >= 'A' && t <= 'F') {
+ c += ((t - 'A') + 10 ) * pows(16,count);
+ } else if (t >= '0' && t <= '9'){
+ c += (t - '0') * pows(16,count);
+ } else {
+ c = -1;
+ }
+ }
+ return c;
+}
+
+char * get_hexbuffer(char *data_buffer, char *hex_buffer)
+{
+ char * ptr = data_buffer;
+ int index = 0;
+ while (*ptr && *++ptr) {
+ *(hex_buffer + index++) = string2hex(ptr-1, 2);
+ ptr++;
+ }
+ *(hex_buffer + index) = 0;
+ return hex_buffer;
+}
+
+int i2c_trans_data(int bus_id, int address, char *buf, int count, unsigned int ext_flag,int timing)
+{
+ int ret;
+
+ struct i2c_msg msg;
+ struct i2c_adapter *adap;
+ adap = i2c_get_adapter(bus_id);
+ if (!adap) return -1;
+
+ msg.addr = address;
+ msg.flags = ((ext_flag & 0x80000000)?I2C_M_RD:0);
+ msg.timing = timing;
+ msg.len = count;
+ msg.buf = (char *)buf;
+ msg.ext_flag = ext_flag & 0x7FFFFFFF;
+// msg.ext_flag = (ext_flag & 0x7FFF00FF);
+// msg.addr |= ext_flag & 0x0000FF00;
+ ret = i2c_transfer(adap, &msg, 1);
+
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ i2c_put_adapter(adap);
+ return (ret == 1) ? count : ret;
+}
+int mt_i2c_test(int id, int addr)
+{
+ int ret = 0;
+ unsigned long flag;
+ unsigned char buffer[]={0x55};
+ if(id >3)
+ flag = I2C_DIRECTION_FLAG;
+
+ flag |= 0x80000000;
+ ret = i2c_trans_data(id, addr,buffer,1,flag,200);
+ return ret;
+}
+EXPORT_SYMBOL(mt_i2c_test);
+
+//extern mt_i2c ;
+static int i2c_test_reg(int bus_id,int val)
+{
+ int ret=0;
+ struct i2c_adapter *adap;
+ mt_i2c *i2c;
+ adap = i2c_get_adapter(bus_id);
+ if (!adap) return -1;
+ i2c = container_of(adap,mt_i2c,adap);
+ printk("I2C%d base address %8x\n",bus_id,i2c->base);
+ //write i2c writable register with 0
+ i2c_writel(i2c,OFFSET_SLAVE_ADDR,val);
+ i2c_writel(i2c,OFFSET_INTR_MASK,val);
+ i2c_writel(i2c,OFFSET_INTR_STAT,val);
+ i2c_writel(i2c,OFFSET_CONTROL,val);
+ i2c_writel(i2c,OFFSET_TRANSFER_LEN,val);
+ i2c_writel(i2c,OFFSET_TRANSAC_LEN,val);
+ i2c_writel(i2c,OFFSET_DELAY_LEN,val);
+ i2c_writel(i2c,OFFSET_TIMING,val);
+ i2c_writel(i2c,OFFSET_EXT_CONF,val);
+ i2c_writel(i2c,OFFSET_IO_CONFIG,val);
+ i2c_writel(i2c,OFFSET_HS,val);
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ i2c_put_adapter(adap);
+ return ret;
+}
+static int i2c_soft_reset(int bus_id)
+{
+ int ret=0;
+ struct i2c_adapter *adap;
+ mt_i2c *i2c;
+ adap = i2c_get_adapter(bus_id);
+ if (!adap) return -1;
+ i2c = container_of(adap,mt_i2c,adap);
+ printk("I2C%d base address %8x\n",bus_id,i2c->base);
+ //write i2c writable register with 0
+ i2c_writel(i2c,OFFSET_SOFTRESET,1);
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ i2c_put_adapter(adap);
+ return ret;
+}
+static int i2c_ext_conf_test(int bus_id,int val)
+{
+ int ret=0;
+ struct i2c_adapter *adap;
+ mt_i2c *i2c;
+ adap = i2c_get_adapter(bus_id);
+ if (!adap) return -1;
+ i2c = container_of(adap,mt_i2c,adap);
+ printk("I2C%d base address %8x\n",bus_id,i2c->base);
+ //write i2c writable register with 0
+ i2c_writel(i2c,OFFSET_EXT_CONF,val);
+ printk("EXT_CONF 0x%x",i2c_readl(i2c,OFFSET_EXT_CONF));
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ i2c_put_adapter(adap);
+ return ret;
+}
+static void hex2string(unsigned char * in, unsigned char * out, int length)
+{
+ unsigned char * ptr = in;
+ unsigned char * ptrout = out;
+ unsigned char t;
+
+ while ( length-- ) {
+ t = (*ptr & 0xF0) >> 4 ;
+ if ( t < 10 ) *ptrout = t + '0';
+ else *ptrout = t + 'A' - 10;
+
+ ptrout++;
+
+ t = (*ptr & 0x0F);
+ if ( t < 10 ) *ptrout = t + '0';
+ else *ptrout = t + 'A' - 10;
+
+ ptr++;
+ ptrout++;
+ }
+ *ptrout = 0;
+}
+
+static ssize_t set_config(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int bus_id;
+ int address;
+ int operation;
+ int trans_mode;
+ int trans_stop;
+ int speed_mode;
+ int pushpull_mode;
+ int query_mode;
+ int timing;
+ int trans_num;
+ int trans_auxlen;
+ int dir=0;
+
+ int number = 0;
+ int length = 0;
+ unsigned int ext_flag = 0;
+ dma_addr_t dma_addr = 0;
+ void * vir_addr = NULL;
+ //int status;
+ int ret = 0;
+
+ unsigned char tmpbuffer[128];
+ printk("%s\n", buf);
+ //if ( sscanf(buf, "%d %d %d %d %d %d %d %d %d %d %d %d %s", &bus_id, &address, &operation, &trans_mode, &trans_stop, &speed_mode, &pushpull_mode, &query_mode, &timing, &trans_num, &trans_auxlen,&dir, data_buffer) ) {
+ if ( sscanf(buf, "%d %x %d %d %d %d %d %d %d %d %d %s", &bus_id, &address, &operation, &trans_mode, &trans_stop, &speed_mode, &pushpull_mode, &query_mode, &timing, &trans_num, &trans_auxlen,data_buffer) ) {
+ if((address != 0)&&(operation<=2)){
+ length = strlen(data_buffer);
+ if (operation == 0){
+ ext_flag |= I2C_WR_FLAG;
+ number = (trans_auxlen << 8 ) | (length >> 1);
+ } else if (operation == 1) {
+ ext_flag |= 0x80000000;
+ number = (trans_num << 8 ) | (length >> 1);
+ } else if (operation == 2) {
+ ext_flag &= 0x7FFFFFFF;
+ number = (trans_num << 8 ) | (length >> 1);
+ } else {
+
+ printk("invalid operation\n");
+ goto err;
+ }
+ if(dir > 0)
+ ext_flag |= I2C_DIRECTION_FLAG;
+
+ if (trans_mode == 0){
+ //default is fifo
+ } else if (trans_mode == 1) {
+ ext_flag |= I2C_DMA_FLAG;
+ } else {
+
+ printk("invalid trans_mod fifo/dma\n");
+ goto err;
+ }
+
+ if (trans_stop == 0) {
+ //default
+ } else if (trans_stop == 1) {
+ ext_flag |= I2C_RS_FLAG;
+ } else {
+
+ printk("invalid trans_stop\n");
+ goto err;
+ }
+
+ if (speed_mode == 0) {
+ timing = 0;//ST mode
+ } else if (speed_mode == 1) {
+ //ext_flag |= I2C_FS_FLAG;//FS MODE
+ } else if (speed_mode == 2) {
+ ext_flag |= I2C_HS_FLAG;//HS mode
+ } else {
+ printk("invalid speed_mode\n");
+ goto err;
+ }
+
+ if (pushpull_mode == 0){
+ //default
+ } else if (pushpull_mode == 1) {
+ ext_flag |= I2C_PUSHPULL_FLAG;
+ } else {
+
+ printk("invalid pushpull mode\n");
+ goto err;
+ }
+
+ if ( query_mode == 0 ){
+ //
+ } else if (query_mode == 1) {
+ ext_flag |= I2C_POLLING_FLAG;
+ } else {
+
+ printk("invalid query mode interrupt/polling\n");
+ goto err;
+ }
+
+ if (trans_mode == 1) {/*DMA MODE*/
+ vir_addr = dma_alloc_coherent(NULL, length >> 1, &dma_addr, GFP_KERNEL);
+ if ( vir_addr == NULL ){
+
+ printk("alloc dma memory failed\n");
+ goto err;
+ }
+ } else {
+ vir_addr = kzalloc(length >> 1, GFP_KERNEL);
+ if ( vir_addr == NULL){
+
+ printk("alloc virtual memory failed\n");
+ goto err;
+ }
+ }
+
+ get_hexbuffer(data_buffer, vir_addr);
+ printk(KERN_ALERT"bus_id:%d,address:%x,count:%x,ext_flag:0x%x,timing:%d\n", bus_id,address,number,ext_flag,timing);
+ printk(KERN_ALERT"data_buffer:%s\n", data_buffer);
+
+ if ( trans_mode == 1 ){
+ /*DMA*/
+ ret = i2c_trans_data(bus_id, address, (void *)dma_addr, number, ext_flag, timing);
+ } else {
+ ret = i2c_trans_data(bus_id, address, vir_addr, number, ext_flag, timing);
+ }
+
+ //dealing
+
+ if ( ret >= 0) {
+
+ if ( operation == 1 ) {
+ hex2string(vir_addr, tmpbuffer, length >> 1);
+ sprintf(data_buffer, "1 %s", tmpbuffer);
+ } else if ( operation == 0 ){
+ hex2string(vir_addr, tmpbuffer, trans_auxlen);
+ sprintf(data_buffer, "1 %s", tmpbuffer);
+ } else {
+ sprintf(data_buffer, "1 %s", "00");
+ }
+ printk("Actual return Value:%d %p\n",ret, vir_addr);
+ } else if ( ret < 0 ) {
+
+ if ( ret == -EINVAL) {
+ sprintf(data_buffer, "0 %s", "Invalid Parameter");
+ } else if ( ret == -ETIMEDOUT ) {
+ sprintf(data_buffer, "0 %s", "Transfer Timeout");
+ } else if ( ret == -EREMOTEIO ) {
+ sprintf(data_buffer, "0 %s", "Ack Error");
+ } else {
+ sprintf(data_buffer, "0 %s", "unknow error");
+ }
+ printk("Actual return Value:%d %p\n",ret, vir_addr);
+ }
+
+ if (trans_mode == 1 && vir_addr != NULL) {/*DMA MODE*/
+ dma_free_coherent(NULL, length >> 1, vir_addr, dma_addr);
+ } else {
+ if (vir_addr)
+ kfree(vir_addr);
+ }
+ //log for UT test.
+ {
+ struct i2c_adapter *adap= i2c_get_adapter(bus_id);
+ mt_i2c *i2c = i2c_get_adapdata(adap);
+ _i2c_dump_info(i2c);
+ }
+ }else{
+ struct i2c_adapter *adap= i2c_get_adapter(bus_id);
+ mt_i2c *i2c = i2c_get_adapdata(adap);
+ if(operation == 3){
+ _i2c_dump_info(i2c);
+ }else if(operation == 4){
+ i2c_test_reg(bus_id,0);
+ _i2c_dump_info(i2c);
+ i2c_test_reg(bus_id,0xFFFFFFFF);
+ _i2c_dump_info(i2c);
+ }else if(operation == 5){
+ i2c_ext_conf_test(bus_id,address);
+ }else if(operation == 9){
+ i2c_soft_reset(bus_id);
+ _i2c_dump_info(i2c);
+ }else if(operation == 6){
+ if(bus_id == 0){
+ //I2C0 PINMUX2 power on
+ #ifdef CONFIG_MTK_PMIC_MT6397
+ #else
+ hwPowerOn(MT65XX_POWER_LDO_VMC1,VOL_DEFAULT,"i2c_pinmux");
+ hwPowerOn(MT65XX_POWER_LDO_VMCH1,VOL_DEFAULT,"i2c_pinmux");
+ #endif
+ }
+
+ }else if(operation == 7){
+ mt_i2c_test(1,0x50);
+ }else{
+ dev_err(dev, "i2c debug system: Parameter invalid!\n");
+ }
+ _i2c_dump_info(i2c);
+
+ }
+ } else {
+ /*parameter invalid*/
+ dev_err(dev, "i2c debug system: Parameter invalid!\n");
+ }
+
+ return count;
+err:
+ printk("analyze failed\n");
+ return -1;
+}
+
+static DEVICE_ATTR(ut, 660, show_config, set_config);
+
+static int __init i2c_common_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ //your code here£¬your should save client in your own way
+ printk(KERN_ALERT"i2c_common device probe\n");
+ ret = device_create_file(&pdev->dev, &dev_attr_ut);
+ return ret;
+}
+
+static int __exit i2c_common_remove(struct platform_device *pdev)
+{
+ int ret = 0;
+ //your code here
+ device_remove_file(&pdev->dev, &dev_attr_ut);
+ return ret;
+}
+
+static struct platform_driver i2c_common_driver= {
+ .driver = {
+ .name = "mt-i2cd",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = i2c_common_probe,
+ .remove = i2c_common_remove,
+};
+
+
+//platfrom device
+static struct platform_device i2c_common_device = {
+ .name = "mt-i2cd",
+};
+
+static int __init xxx_init( void )
+{
+ printk(KERN_ALERT"i2c_common device init\n");
+ platform_device_register(&i2c_common_device);
+ return platform_driver_register(&i2c_common_driver);
+}
+
+static void __exit xxx_exit(void)
+{
+ platform_driver_unregister(&i2c_common_driver);
+ platform_device_unregister(&i2c_common_device);
+}
+
+module_init( xxx_init );
+module_exit( xxx_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MediaTek I2C Bus Driver Test Driver");
+MODULE_AUTHOR("Ranran Lu");
+