626 lines
14 KiB
C
626 lines
14 KiB
C
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||
|
/*
|
||
|
* Copyright (c) 2019 MediaTek Inc.
|
||
|
*/
|
||
|
|
||
|
#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 <linux/delay.h>
|
||
|
#include "i2c-mtk.h"
|
||
|
/* filer out error messages */
|
||
|
|
||
|
static char data_buffer[256 * 4];
|
||
|
unsigned long long t3, t4, t5, t6;
|
||
|
|
||
|
static inline void i2c_writew_d(struct mt_i2c *i2c, u8 offset, u16 value)
|
||
|
{
|
||
|
writew(value, (void *)((i2c->base) + (offset)));
|
||
|
}
|
||
|
|
||
|
static inline u16 i2c_readw_d(struct mt_i2c *i2c, u8 offset)
|
||
|
{
|
||
|
return readw((void const *)((i2c->base) + (offset)));
|
||
|
}
|
||
|
|
||
|
int mt_i2c_test(int id, int addr)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
/* ret = i2c_trans_data(id, addr, buffer,,buffer, 1, 1, 0); */
|
||
|
return ret;
|
||
|
}
|
||
|
EXPORT_SYMBOL(mt_i2c_test);
|
||
|
|
||
|
int mt_i2c_test_multi_wr(int id, int addr)
|
||
|
{
|
||
|
int ret;
|
||
|
struct i2c_msg msg[12];
|
||
|
struct i2c_adapter *adap;
|
||
|
char buf0[3] = {0x55, 0x00, 0x01};
|
||
|
char buf1[3] = {0x55, 0x01, 0x02};
|
||
|
char buf2[3] = {0x55, 0x02, 0x03};
|
||
|
char buf3[3] = {0x55, 0x03, 0x04};
|
||
|
char buf4[2] = {0x55, 0x00};
|
||
|
char buf5[2] = {0xff, 0xff};
|
||
|
char buf6[2] = {0x55, 0x01};
|
||
|
char buf7[2] = {0xff, 0xff};
|
||
|
char buf8[2] = {0x55, 0x02};
|
||
|
char buf9[2] = {0xff, 0xff};
|
||
|
char buf10[2] = {0x55, 0x03};
|
||
|
char buf11[2] = {0xff, 0xff};
|
||
|
|
||
|
adap = i2c_get_adapter(id);
|
||
|
if (!adap)
|
||
|
return -1;
|
||
|
|
||
|
msg[0].addr = addr;
|
||
|
msg[0].flags = 0;
|
||
|
msg[0].len = 3;
|
||
|
msg[0].buf = buf0;
|
||
|
msg[1].addr = addr;
|
||
|
msg[1].flags = 0;
|
||
|
msg[1].len = 3;
|
||
|
msg[1].buf = buf1;
|
||
|
msg[2].addr = addr;
|
||
|
msg[2].flags = 0;
|
||
|
msg[2].len = 3;
|
||
|
msg[2].buf = buf2;
|
||
|
msg[3].addr = addr;
|
||
|
msg[3].flags = 0;
|
||
|
msg[3].len = 3;
|
||
|
msg[3].buf = buf3;
|
||
|
msg[4].addr = addr;
|
||
|
msg[4].flags = 0;
|
||
|
msg[4].len = 2;
|
||
|
msg[4].buf = buf4;
|
||
|
msg[5].addr = addr;
|
||
|
msg[5].flags = I2C_M_RD;
|
||
|
msg[5].len = 1;
|
||
|
msg[5].buf = buf5;
|
||
|
msg[6].addr = addr;
|
||
|
msg[6].flags = 0;
|
||
|
msg[6].len = 2;
|
||
|
msg[6].buf = buf6;
|
||
|
msg[7].addr = addr;
|
||
|
msg[7].flags = I2C_M_RD;
|
||
|
msg[7].len = 1;
|
||
|
msg[7].buf = buf7;
|
||
|
msg[8].addr = addr;
|
||
|
msg[8].flags = 0;
|
||
|
msg[8].len = 2;
|
||
|
msg[8].buf = buf8;
|
||
|
msg[9].addr = addr;
|
||
|
msg[9].flags = I2C_M_RD;
|
||
|
msg[9].len = 1;
|
||
|
msg[9].buf = buf9;
|
||
|
msg[10].addr = addr;
|
||
|
msg[10].flags = 0;
|
||
|
msg[10].len = 2;
|
||
|
msg[10].buf = buf10;
|
||
|
msg[11].addr = addr;
|
||
|
msg[11].flags = I2C_M_RD;
|
||
|
msg[11].len = 1;
|
||
|
msg[11].buf = buf11;
|
||
|
hw_trig_i2c_enable(adap);
|
||
|
ret = hw_trig_i2c_transfer(adap, msg, 4);
|
||
|
hw_trig_i2c_disable(adap);
|
||
|
pr_info("camera 0x5500 : %x 0x5501 : %x 0x5502 : %x 0x5503 : %x .\n",
|
||
|
buf5[0], buf7[0], buf9[0], buf11[0]);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int mt_i2c_test_wrrd(int id, int addr, int wr_len, int rd_len,
|
||
|
char *wr_buf, char *rd_buf, unsigned int speedhz)
|
||
|
{
|
||
|
|
||
|
int ret;
|
||
|
struct i2c_msg msg[2];
|
||
|
struct i2c_adapter *adap;
|
||
|
struct mt_i2c *i2c;
|
||
|
unsigned int origin_speed = 0;
|
||
|
|
||
|
adap = i2c_get_adapter(id);
|
||
|
if (!adap)
|
||
|
return -1;
|
||
|
|
||
|
i2c = container_of(adap, struct mt_i2c, adap);
|
||
|
if (speedhz) {
|
||
|
origin_speed = i2c->speed_hz;
|
||
|
i2c->speed_hz = speedhz;
|
||
|
}
|
||
|
|
||
|
msg[0].addr = addr;
|
||
|
msg[0].flags = 0;
|
||
|
msg[0].len = wr_len;
|
||
|
msg[0].buf = wr_buf;
|
||
|
/*
|
||
|
* for(i = 0; i < wr_len; i++) {
|
||
|
* printk("cxd wr_len = %d i2c_trans_data-%d = 0x%x\n",
|
||
|
* wr_len, i, wr_buf[i]);
|
||
|
* }
|
||
|
*/
|
||
|
msg[1].addr = addr;
|
||
|
msg[1].flags = I2C_M_RD;
|
||
|
msg[1].len = rd_len;
|
||
|
msg[1].buf = rd_buf;
|
||
|
|
||
|
ret = i2c_transfer(adap, &msg[0], 2);
|
||
|
/*
|
||
|
* printk("cxd i2c_trans_ret = %d\n", ret);
|
||
|
* for(ii = 0; ii<rd_len; ii++)
|
||
|
* printk("cxd i2c_trans_data-%d = 0x%x\n", ii, rd_buf[ii]);
|
||
|
*/
|
||
|
if (origin_speed)
|
||
|
i2c->speed_hz = origin_speed;
|
||
|
|
||
|
return ret;
|
||
|
|
||
|
}
|
||
|
|
||
|
static ssize_t show_config(struct device *dev, struct device_attribute *attr,
|
||
|
char *buff)
|
||
|
{
|
||
|
int len = strlen(data_buffer);
|
||
|
|
||
|
pr_info("Usage echo \"[bus_id] [address] [operation] [w_count]\n"
|
||
|
"[r_count] [data]\" > ut\n");
|
||
|
memcpy(buff, data_buffer, len);
|
||
|
pr_info("Return Value:%s\n\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_wr, char *buf_rd,
|
||
|
int operation, int len_wr, int len_rd, unsigned int speedhz)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
struct i2c_msg msg;
|
||
|
struct i2c_adapter *adap;
|
||
|
struct mt_i2c *i2c;
|
||
|
unsigned int origin_speed = 0;
|
||
|
|
||
|
adap = i2c_get_adapter(bus_id);
|
||
|
if (!adap)
|
||
|
return -1;
|
||
|
|
||
|
i2c = container_of(adap, struct mt_i2c, adap);
|
||
|
if (speedhz) {
|
||
|
origin_speed = i2c->speed_hz;
|
||
|
i2c->speed_hz = speedhz;
|
||
|
}
|
||
|
|
||
|
msg.addr = address;
|
||
|
if (operation == 2) {
|
||
|
msg.flags = I2C_M_RD;
|
||
|
msg.len = len_rd;
|
||
|
msg.buf = (char *)buf_rd;
|
||
|
} else {
|
||
|
msg.flags = 0;
|
||
|
msg.len = len_wr;
|
||
|
msg.buf = (char *)buf_wr;
|
||
|
}
|
||
|
ret = i2c_transfer(adap, &msg, 1);
|
||
|
/*
|
||
|
*if(ret > 0) {
|
||
|
* for(i = 0; i<msg.len; i++)
|
||
|
* printk("cxd i2c_trans_data-%d = 0x%x\n",
|
||
|
* i, msg.buf[i]);
|
||
|
*
|
||
|
*}
|
||
|
*/
|
||
|
if (origin_speed)
|
||
|
i2c->speed_hz = origin_speed;
|
||
|
|
||
|
i2c_put_adapter(adap);
|
||
|
return (ret == 1) ? msg.len : ret;
|
||
|
}
|
||
|
|
||
|
/* extern mt_i2c ; */
|
||
|
static int i2c_test_reg(int bus_id, int val)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
struct i2c_adapter *adap;
|
||
|
struct mt_i2c *i2c;
|
||
|
|
||
|
adap = i2c_get_adapter(bus_id);
|
||
|
if (!adap)
|
||
|
return -1;
|
||
|
i2c = container_of(adap, struct mt_i2c, adap);
|
||
|
/* printk("I2C%d base address %8x\n", bus_id,
|
||
|
* (unsigned int)(i2c->base));
|
||
|
*/
|
||
|
/* write i2c writable register with 0 */
|
||
|
i2c_writew_d(i2c, OFFSET_SLAVE_ADDR, val);
|
||
|
i2c_writew_d(i2c, OFFSET_INTR_MASK, val);
|
||
|
i2c_writew_d(i2c, OFFSET_INTR_STAT, val);
|
||
|
i2c_writew_d(i2c, OFFSET_CONTROL, val);
|
||
|
i2c_writew_d(i2c, OFFSET_TRANSFER_LEN, val);
|
||
|
i2c_writew_d(i2c, OFFSET_TRANSAC_LEN, val);
|
||
|
i2c_writew_d(i2c, OFFSET_DELAY_LEN, val);
|
||
|
i2c_writew_d(i2c, OFFSET_TIMING, val);
|
||
|
i2c_writew_d(i2c, OFFSET_EXT_CONF, val);
|
||
|
i2c_writew_d(i2c, OFFSET_IO_CONFIG, val);
|
||
|
i2c_writew_d(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;
|
||
|
struct mt_i2c *i2c;
|
||
|
|
||
|
adap = i2c_get_adapter(bus_id);
|
||
|
if (!adap)
|
||
|
return -1;
|
||
|
i2c = container_of(adap, struct mt_i2c, adap);
|
||
|
/* printk("I2C%d base address %8x\n", bus_id,
|
||
|
* (unsigned int)(i2c->base));
|
||
|
*/
|
||
|
/* write i2c writable register with 0 */
|
||
|
i2c_writew_d(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;
|
||
|
struct mt_i2c *i2c;
|
||
|
|
||
|
adap = i2c_get_adapter(bus_id);
|
||
|
if (!adap)
|
||
|
return -1;
|
||
|
i2c = container_of(adap, struct mt_i2c, adap);
|
||
|
/* printk("I2C%d base address %8x\n", bus_id,
|
||
|
* (unsigned int)(i2c->base));
|
||
|
*/
|
||
|
/* write i2c writable register with 0 */
|
||
|
i2c_writew_d(i2c, OFFSET_EXT_CONF, val);
|
||
|
/* printk("EXT_CONF 0x%x", i2c_readw_d(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;
|
||
|
}
|
||
|
|
||
|
unsigned long long fail_time;
|
||
|
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 wr_number = 0;
|
||
|
int rd_number = 0;
|
||
|
unsigned int speedhz = 0;
|
||
|
char *buf_test;
|
||
|
|
||
|
int length = 0;
|
||
|
void *vir_addr_wr = NULL;
|
||
|
void *vir_addr_rd = NULL;
|
||
|
/* int status; */
|
||
|
int ret = 0;
|
||
|
int scanf_ret = 0;
|
||
|
unsigned char tmpbuffer[128];
|
||
|
|
||
|
pr_info("%s\n", buf);
|
||
|
scanf_ret = sscanf(buf, "%d %x %d %d %d %d %1023s",
|
||
|
&bus_id, &address, &operation,
|
||
|
&wr_number, &rd_number, &speedhz,
|
||
|
data_buffer);
|
||
|
if (scanf_ret) {
|
||
|
pr_info("bus_id:%d,address:%x,operation:0x%x, speed:%d\n",
|
||
|
bus_id, address, operation, speedhz);
|
||
|
if ((address != 0) && (operation <= 2)) {
|
||
|
length = strlen(data_buffer);
|
||
|
|
||
|
if (operation == 1) {
|
||
|
if ((length >> 1) != wr_number)
|
||
|
pr_info("Error length of data number = %d,length = %d\n",
|
||
|
wr_number, length >> 1);
|
||
|
vir_addr_wr = kzalloc(wr_number, GFP_KERNEL);
|
||
|
if (vir_addr_wr == NULL) {
|
||
|
|
||
|
pr_info("alloc virtual memory failed\n");
|
||
|
goto err;
|
||
|
}
|
||
|
get_hexbuffer(data_buffer, vir_addr_wr);
|
||
|
pr_info("data_buffer:%s\n", data_buffer);
|
||
|
|
||
|
|
||
|
}
|
||
|
if (operation == 2) {
|
||
|
vir_addr_rd = kzalloc(rd_number, GFP_KERNEL);
|
||
|
if (vir_addr_rd == NULL) {
|
||
|
|
||
|
pr_info("alloc virtual memory failed\n");
|
||
|
goto err;
|
||
|
}
|
||
|
}
|
||
|
if (operation == 0) {
|
||
|
vir_addr_wr = kzalloc(wr_number, GFP_KERNEL);
|
||
|
if (vir_addr_wr == NULL) {
|
||
|
|
||
|
pr_info("alloc virtual memory failed\n");
|
||
|
goto err;
|
||
|
}
|
||
|
vir_addr_rd = kzalloc(rd_number, GFP_KERNEL);
|
||
|
if (vir_addr_rd == NULL) {
|
||
|
kfree(vir_addr_wr);
|
||
|
pr_info("alloc virtual memory failed\n");
|
||
|
goto err;
|
||
|
}
|
||
|
get_hexbuffer(data_buffer, vir_addr_wr);
|
||
|
pr_info("data_buffer:%s\n", data_buffer);
|
||
|
}
|
||
|
|
||
|
if (operation == 0) { /* 0:WRRD 1:WR 2:RD */
|
||
|
t3 = sched_clock();
|
||
|
/* while (1) { */
|
||
|
/* msleep(500);*/
|
||
|
ret = mt_i2c_test_wrrd(bus_id, address,
|
||
|
wr_number,
|
||
|
rd_number,
|
||
|
vir_addr_wr,
|
||
|
vir_addr_rd, speedhz);
|
||
|
/* buf_test = (char *)vir_addr_rd;
|
||
|
* if (buf_test[0] != 0x75) {
|
||
|
* fail_time++;
|
||
|
* pr_info("I2C press fail_time=%llu\n",
|
||
|
* fail_time);
|
||
|
* }
|
||
|
* }
|
||
|
*/
|
||
|
t4 = sched_clock();
|
||
|
/* pr_info("test i2c wr-rd:hw time=%llu,
|
||
|
* total=%llu\n", t2-t1, t4-t3);
|
||
|
*/
|
||
|
} else {
|
||
|
t5 = sched_clock();
|
||
|
ret = i2c_trans_data(bus_id, address,
|
||
|
vir_addr_wr, vir_addr_rd,
|
||
|
operation, wr_number,
|
||
|
rd_number, speedhz);
|
||
|
buf_test = (char *)vir_addr_rd;
|
||
|
|
||
|
t6 = sched_clock();
|
||
|
/* pr_info("test i2c :hw time=%llu,total=%llu\n",
|
||
|
* t2-t1, t6-t5);
|
||
|
*/
|
||
|
}
|
||
|
/* dealing */
|
||
|
|
||
|
if (ret >= 0) {
|
||
|
if (operation == 2) {
|
||
|
hex2string(vir_addr_rd, tmpbuffer,
|
||
|
rd_number);
|
||
|
snprintf(data_buffer,
|
||
|
sizeof(data_buffer),
|
||
|
"1 %s", tmpbuffer);
|
||
|
pr_info("Actual return Value:%d %s\n",
|
||
|
ret, data_buffer);
|
||
|
} else if (operation == 0) {
|
||
|
hex2string(vir_addr_rd, tmpbuffer,
|
||
|
rd_number);
|
||
|
snprintf(data_buffer,
|
||
|
sizeof(data_buffer),
|
||
|
"1 %s", tmpbuffer);
|
||
|
pr_info("Actual return Value:%d %s\n",
|
||
|
ret, data_buffer);
|
||
|
if (strncmp(tmpbuffer, "68", 1)) {
|
||
|
fail_time++;
|
||
|
pr_info("data_buffer != 68, fail time=%llu\n",
|
||
|
fail_time);
|
||
|
}
|
||
|
} else {
|
||
|
snprintf(data_buffer,
|
||
|
sizeof(data_buffer),
|
||
|
"1 %s", "00");
|
||
|
pr_info("Actual return Value:%d %s\n",
|
||
|
ret, data_buffer);
|
||
|
}
|
||
|
|
||
|
} else if (ret < 0) {
|
||
|
if (ret == -EINVAL)
|
||
|
snprintf(data_buffer,
|
||
|
sizeof(data_buffer),
|
||
|
"0 %s", "Invalid Parameter");
|
||
|
else if (ret == -ETIMEDOUT)
|
||
|
snprintf(data_buffer,
|
||
|
sizeof(data_buffer),
|
||
|
"0 %s", "Transfer Timeout");
|
||
|
else if (ret == -EREMOTEIO)
|
||
|
snprintf(data_buffer,
|
||
|
sizeof(data_buffer),
|
||
|
"0 %s", "Ack Error");
|
||
|
else
|
||
|
snprintf(data_buffer,
|
||
|
sizeof(data_buffer),
|
||
|
"0 %s", "unknown error");
|
||
|
pr_info("Actual return Value:%d %p\n", ret,
|
||
|
data_buffer);
|
||
|
}
|
||
|
kfree(vir_addr_rd);
|
||
|
kfree(vir_addr_wr);
|
||
|
|
||
|
} else {
|
||
|
struct i2c_adapter *adap = i2c_get_adapter(bus_id);
|
||
|
|
||
|
if (adap) {
|
||
|
struct 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) {
|
||
|
mt_i2c_test_multi_wr(bus_id, address);
|
||
|
if (bus_id == 0) {
|
||
|
/* I2C0 PINMUX2 power on */
|
||
|
/* hwPowerOn(MT65XX_POWER_LDO_VMC1,
|
||
|
* VOL_DEFAULT,
|
||
|
* "i2c_pinmux");
|
||
|
*/
|
||
|
/* hwPowerOn(MT65XX_POWER_LDO_VMCH1,
|
||
|
* VOL_DEFAULT,
|
||
|
* "i2c_pinmux");
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
} else if (operation == 7) {
|
||
|
mt_i2c_test(1, 0x50);
|
||
|
} else {
|
||
|
pr_info("i2c debug system: Parameter invalid!\n");
|
||
|
}
|
||
|
} else {
|
||
|
/*adap invalid */
|
||
|
pr_info("i2c debug system: get adap fail!\n");
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
/*parameter invalid */
|
||
|
pr_info("i2c debug system: Parameter invalid!\n");
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
err:
|
||
|
pr_info("analyze failed\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static DEVICE_ATTR(ut, 0660, show_config, set_config);
|
||
|
|
||
|
static int i2c_common_probe(struct i2c_client *client,
|
||
|
const struct i2c_device_id *id)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
/* your code here\A3\ACyour should save client in your own way */
|
||
|
pr_info("i2c_common device probe\n");
|
||
|
ret = device_create_file(&client->dev, &dev_attr_ut);
|
||
|
pr_info("i2c_common device probe ret = %d\n", ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int i2c_common_remove(struct i2c_client *client)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
/* your code here */
|
||
|
device_remove_file(&client->dev, &dev_attr_ut);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static const struct i2c_device_id i2c_common_test_id[] = {
|
||
|
{"mtk-iicd", 0},
|
||
|
{},
|
||
|
};
|
||
|
|
||
|
static const struct of_device_id i2c_common_of_match[] = {
|
||
|
{.compatible = "mediatek,mtk-iicd"},
|
||
|
{},
|
||
|
};
|
||
|
|
||
|
static struct i2c_driver i2c_common_driver = {
|
||
|
.driver = {
|
||
|
.name = "mtk-iicd",
|
||
|
.of_match_table = i2c_common_of_match,
|
||
|
},
|
||
|
.probe = i2c_common_probe,
|
||
|
.remove = i2c_common_remove,
|
||
|
.id_table = i2c_common_test_id,
|
||
|
};
|
||
|
module_i2c_driver(i2c_common_driver);
|
||
|
|
||
|
MODULE_LICENSE("GPL");
|
||
|
MODULE_DESCRIPTION("MediaTek I2C Bus Driver Test Driver");
|
||
|
MODULE_AUTHOR("Ranran Lu");
|