Makefile
KERNEL_DIR=/home/xxx/workspace/RK3399/soap/new_pro/P88/kernel CURDIR=`pwd` ARCH=arm64 CROSS_COMPILE=/home/xxx/workspace/RK3399/soap/new_pro/P88/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- export ARCH CROSS_COMPILE obj-m := husb_ala.o all: make -C $(KERNEL_DIR) M=$(CURDIR) modules .PHONE:clean cp clean: $(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean cp: sudo cp *.ko /home/nfs -rf
创建
husb_ala.c
#include#include #include #include #include #include #include #include #include #define I2C_RETRY_NUMBER 1 struct husb311_ctrl { int gpio; int irq; struct i2c_client * client; }; static struct husb311_ctrl * g_husb311_ctrl = NULL; static DEFINE_MUTEX(i2c_rw_access); int husb311_i2c_read(struct i2c_client *client, char *writebuf, int writelen, char *readbuf, int readlen) { int ret = 0; int i = 0; mutex_lock(&i2c_rw_access); if (readlen > 0) { if (writelen > 0) { struct i2c_msg msgs[] = { { .addr = client->addr, .flags = 0, .len = writelen, .buf = writebuf, }, { .addr = client->addr, .flags = I2C_M_RD, .len = readlen, .buf = readbuf, }, }; for (i = 0; i < I2C_RETRY_NUMBER; i++) { ret = i2c_transfer(client->adapter, msgs, 2); if (ret < 0) { printk(KERN_ERR "[IIC]: i2c_transfer(write) error, ret=%d ,client->addr=0x%x!!", ret,client->addr); } else break; } } else { struct i2c_msg msgs[] = { { .addr = client->addr, .flags = I2C_M_RD, .len = readlen, .buf = readbuf, }, }; for (i = 0; i < I2C_RETRY_NUMBER; i++) { ret = i2c_transfer(client->adapter, msgs, 1); if (ret < 0) { printk(KERN_ERR "[IIC]: i2c_transfer(read) error, ret=%d!!", ret); } else break; } } } mutex_unlock(&i2c_rw_access); return ret; } int husb311_i2c_write(struct i2c_client *client, char *writebuf, int writelen) { int ret = 0; int i = 0; mutex_lock(&i2c_rw_access); if (writelen > 0) { struct i2c_msg msgs[] = { { .addr = client->addr, .flags = 0, .len = writelen, .buf = writebuf, }, }; for (i = 0; i < I2C_RETRY_NUMBER; i++) { ret = i2c_transfer(client->adapter, msgs, 1); if (ret < 0) { printk(KERN_ERR "%s: i2c_transfer(write) error, ret=%d", __func__, ret); } else break; } } mutex_unlock(&i2c_rw_access); return ret; } int husb311_i2c_write_reg(struct i2c_client *client, unsigned char regaddr, unsigned char regvalue) { unsigned char buf[2] = {0}; buf[0] = regaddr; buf[1] = regvalue; return husb311_i2c_write(client, buf, sizeof(buf)); } int husb311_i2c_read_reg(struct i2c_client *client, unsigned char regaddr, unsigned char *regvalue) { return husb311_i2c_read(client, ®addr, 1, regvalue, 1); } static int husb311_i2c_read_regs(struct i2c_client *client, unsigned char cmd, unsigned char *data, unsigned char data_len) { struct i2c_msg msgs[2]; int ret = -1; unsigned char * buffer = NULL; buffer = kzalloc(data_len, GFP_KERNEL); if (!buffer) return -ENOMEM; msgs[0].addr = client->addr; msgs[0].flags = client->flags; msgs[0].len = 1; msgs[0].buf = &cmd; msgs[1].addr = client->addr; msgs[1].flags = client->flags | I2C_M_RD; msgs[1].len = data_len; msgs[1].buf = buffer; ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (ret < 0) dev_err(&client->adapter->dev, "i2c read failedn"); else memcpy(data, buffer, data_len); kfree(buffer); return ret; } static int husb311_i2c_write_regs(struct i2c_client *client, unsigned char cmd, unsigned char *data, unsigned char data_len) { struct i2c_msg msgs[1]; unsigned char *buffer; int ret = 0; buffer = kzalloc(data_len + 1, GFP_KERNEL); if (!buffer) return -ENOMEM; buffer[0] = cmd; memcpy(buffer + 1, data, data_len); msgs[0].addr = client->addr; msgs[0].flags = client->flags; msgs[0].len = data_len + 1; msgs[0].buf = buffer; ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (ret < 0) dev_err(&client->adapter->dev, "i2c write failedn"); kfree(buffer); return ret; } static int husb311_i2c_write_reg(struct i2c_client *client, unsigned char reg, unsigned char value) { unsigned char buf[2] = {' '}; buf[0] = value; buf[1] = ' '; return husb311_i2c_write_regs(client, reg, buf, 1); } static unsigned char husb311_i2c_read_reg(struct i2c_client *client, unsigned char reg) { int ret = -1; unsigned char buf[2] = {' '}; ret = husb311_i2c_read_regs(client, reg, buf, 1); if (ret < 0) { printk(KERN_ERR "husb311_i2c_read_regs 0x%x failn", reg); return -1; } return buf[0]; } static int husb311_init(struct i2c_client * client) { int ret = -1; //unsigned char value = 0; //unsigned char i = 0; ret = husb311_i2c_write_reg(client, 0xA0, 0x1); if (ret < 0) { printk(KERN_ERR "husb311_i2c_write_reg 0xA0 failn"); return -1; } for (;;) { ret = husb311_i2c_read_reg(client, 0x1E, &value); if (ret) { printk(KERN_ERR "time out!!!n"); return -1; } if (!(value & (1 << 6)) || (i > 20)) { break; } msleep(100); i++; } if (i > 20) { printk(KERN_ERR "time out!!!n"); return -1; } ret = husb311_i2c_write_reg(client, 0x10, 0xff); if (ret < 0) { printk(KERN_ERR "husb311_i2c_write_reg 0x10 failn"); return -1; } ret = husb311_i2c_write_reg(client, 0x11, 0xff); if (ret < 0) { printk(KERN_ERR "husb311_i2c_write_reg 0x11 failn"); return -1; } ret = husb311_i2c_write_reg(client, 0x12, 0x1); if (ret < 0) { printk(KERN_ERR "husb311_i2c_write_reg 0x12 failn"); return -1; } ret = husb311_i2c_write_reg(client, 0x13, 0x0); if (ret < 0) { printk(KERN_ERR "husb311_i2c_write_reg 0x13 failn"); return -1; } ret = husb311_i2c_write_reg(client, 0x14, 0x0); if (ret < 0) { printk(KERN_ERR "husb311_i2c_write_reg 0x14 failn"); return -1; } ret = husb311_i2c_write_reg(client, 0x90, 0x2); if (ret < 0) { printk(KERN_ERR "husb311_i2c_write_reg 0x90 failn"); return -1; } ret = husb311_i2c_write_reg(client, 0x9f, 0x0); if (ret < 0) { printk(KERN_ERR "husb311_i2c_write_reg 0x9f failn"); return -1; } ret = husb311_i2c_write_reg(client, 0x1a, 0xa); if (ret < 0) { printk(KERN_ERR "husb311_i2c_write_reg 0x1a failn"); return -1; } return 0; } static void husb311_func(struct work_struct * work) { unsigned char value = 0; int ret = husb311_i2c_read_reg(g_husb311_ctrl->client, 0x10, &value); if (ret) { printk(KERN_ERR "husb311_i2c_write_reg 0x10 failn"); return; } if (value &(1 << 0)) { ret = husb311_i2c_read_reg(g_husb311_ctrl->client, 0x1d, &value); if (ret) { printk(KERN_ERR "husb311_i2c_write_reg 0x1d failn"); return; } if ((value & (0x3 << 2)) && ((value & (0x3 << 0))==0x0)) { printk(KERN_ERR "CC2 is connect!!!"); } if ((value & (0x3 << 0)) && ((value & (0x3 << 2))==0x0)) { printk(KERN_ERR "CC1 is connect!!!"); } husb311_i2c_write_reg(g_husb311_ctrl->client, 0x10, 0xff); husb311_i2c_write_reg(g_husb311_ctrl->client, 0x11, 0xff); } enable_irq(g_husb311_ctrl->irq); } static DECLARE_WORK(husb311_work, husb311_func); static irqreturn_t husb311_irq_handler(int irq, void *dev_id) { printk(KERN_ERR "------------husb311_irq_handler-------------n"); schedule_work(&husb311_work); disable_irq(g_husb311_ctrl->irq); return IRQ_HANDLED; } static int husb311_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = -1; enum of_gpio_flags irq_flags; struct device_node * np = client->dev.of_node; printk(KERN_ERR "------------enter probe function-------------n"); g_husb311_ctrl = kzalloc(sizeof(struct husb311_ctrl), GFP_KERNEL); if (!g_husb311_ctrl) { printk(KERN_ERR "kzalloc failn"); return -ENOMEM; } g_husb311_ctrl->client = client; g_husb311_ctrl->gpio = of_get_named_gpio_flags(np, "int-n-gpios", 0, (enum of_gpio_flags*)&irq_flags); if (g_husb311_ctrl->gpio < 0) { printk(KERN_ERR "of_get_named_gpio_flags failn"); goto gpio_err; } printk(KERN_ERR "gpio:%dn", g_husb311_ctrl->gpio); ret = gpio_request(g_husb311_ctrl->gpio, "husb311 irq gpio"); if (ret < 0) { printk(KERN_ERR "gpio_request failn"); goto gpio_request_err; } g_husb311_ctrl->irq = gpio_to_irq(g_husb311_ctrl->gpio); if (g_husb311_ctrl->irq < 0) { printk(KERN_ERR "gpio_to_irq failn"); goto to_irq_err; } printk(KERN_ERR "irq:%dn", g_husb311_ctrl->irq); ret = request_irq(g_husb311_ctrl->irq, husb311_irq_handler, irq_flags, "husb311_irq", NULL); printk(KERN_ERR "request_irq return:%dn", ret); if (ret != 0) { printk(KERN_ERR "request_irq failn"); goto request_irq_err; } ret = husb311_init(client); if (ret < 0) { printk(KERN_ERR "husb311_init failn"); goto husb311_init_err; } return 0; husb311_init_err: free_irq(g_husb311_ctrl->irq, NULL); request_irq_err: to_irq_err: gpio_free(g_husb311_ctrl->gpio); gpio_request_err: gpio_err: return -1; } static int husb311_remove(struct i2c_client *client) { free_irq(g_husb311_ctrl->irq, NULL); gpio_free(g_husb311_ctrl->gpio); return 0; } static const struct of_device_id husb311_of_match[] = { { .compatible = "husb311" }, { }, }; static const struct i2c_device_id husb30x[] = { { "husb311", 0 }, {} }; MODULE_DEVICE_TABLE(i2c, husb30x); static struct i2c_driver husb311_i2c_driver = { .driver = { .name = "husb311", .of_match_table = husb311_of_match, }, .probe = husb311_probe, .remove = husb311_remove, .id_table = husb30x, }; module_i2c_driver(husb311_i2c_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("linqi"); MODULE_DEscriptION("husb311 usb cc driver");



