简单i2c设备驱动实例

来源:互联网 发布:手机群呼软件 编辑:程序博客网 时间:2024/06/05 16:35

平台: msm8916

OS:安卓5.1

usb4604在设备上作用是切换设备为主从模式。


设备树文件如下:

   microchip@2d {compatible = "microchip,usb4604";reg = <0x2d>;                        usbid-gpios = <&msm_gpio 32 0x00>;                        reset-gpios = <&msm_gpio 72 0x00>;            };


usb4604驱动文件:

生成sys/bus/i2c/devices/0-002d/host节点,可以通过echo 0 > sys/bus/i2c/devices/0-002d/host 或者echo 1 > sys/bus/i2c/devices/0-002d/host 来切换主从,即向usb4604对应的寄存器写入对应的值。


/* Copyright (c) 2015 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * 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 <linux/i2c.h>#include <linux/debugfs.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/power_supply.h>#include <linux/regulator/driver.h>#include <linux/regulator/of_regulator.h>#include <linux/regulator/machine.h>#include <linux/gpio.h>#include <linux/of.h>#include <linux/of_gpio.h>#include <linux/mutex.h>#include <linux/delay.h>#include <linux/qpnp/qpnp-adc.h>#include <linux/usb.h>struct usb4604_chip {struct i2c_client *client;bool is_host;int  usbid_gpio;int  reset_gpio;};static int usb4604_i2c_write(struct usb4604_chip *chip, u8 *buf, u8 len){struct i2c_msg msgs ={.addr = chip->client->addr,.flags = chip->client->flags,.len = len,.buf = buf,};return i2c_transfer(chip->client->adapter, &msgs, 1);}static int usb4604_switch(struct usb4604_chip *chip){int ret, i;u8 data[8];if (chip->reset_gpio) {ret = gpio_direction_output(chip->reset_gpio, 0);if (ret) {pr_err("%s: gpio %d output failed. ret = %d\n",__func__, chip->is_host, ret);} else {mdelay(10);ret = gpio_direction_output(chip->reset_gpio, 1);if (ret) {pr_err("%s: gpio %d output failed. ret = %d\n",__func__, chip->is_host, ret);}elsemdelay(10);}}data[0] = 0x00;data[1] = 0x00;data[2] = 0x05;data[3] = 0x00;data[4] = 0x01;data[5] = 0x31;data[6] = 0x8e;data[7] = chip->is_host ? 0x03 : 0x02;//BIT(1)mode BIT(0)enablefor(i = 0; i < 30; i++) {ret = usb4604_i2c_write(chip, data, 8);if(ret > 0)break;pr_err("###############mdelay %d\n", i);mdelay(10);}if(ret < 0)return ret;data[0] = 0x99;data[1] = 0x37;data[2] = 0x00;ret = usb4604_i2c_write(chip, data, 3);data[0] = 0xaa;data[1] = 0x55;data[2] = 0x00;ret = usb4604_i2c_write(chip, data, 3);pr_err("@@@@usb4604_switch %d\n", ret);if(ret > 0) {ret = gpio_direction_output(chip->usbid_gpio, chip->is_host);if (ret) {pr_err("%s: gpio %d output failed. ret = %d\n",__func__, chip->is_host, ret);}}elsepr_err("@@@@usb4604_switch I2C ERROR\n");return ret;}static ssize_t host_show(struct device *dev,   struct device_attribute *attr, char *buf){struct usb4604_chip *chip = dev_get_drvdata(dev);return snprintf(buf, PAGE_SIZE, "%d\n", chip->is_host);}static ssize_t host_store(struct device *dev,   struct device_attribute *attr,   const char *buff, size_t size){struct usb4604_chip *chip = dev_get_drvdata(dev);long host;int ret;if (kstrtol(buff, 10, (long *)&host)) {pr_err("can not recognize\n");return size;}if (!!host != chip->is_host) {chip->is_host = !!host;ret = usb4604_switch(chip);pr_info("@@@@host_store %d, ret = %d\n", chip->is_host, ret);} else {pr_info("the same as old %d", chip->is_host);}return size;}static ssize_t reset_store(struct device *dev,   struct device_attribute *attr,   const char *buff, size_t size){struct usb4604_chip *chip = dev_get_drvdata(dev);long reset;int ret;if(kstrtol(buff, 10, (long *)&reset)) {pr_err("can not recognize\n");return size;}if(chip->reset_gpio) {ret = gpio_direction_output(chip->reset_gpio, !!reset);if (ret) {pr_err("%s: gpio %d output failed. ret = %d\n",__func__, chip->reset_gpio, ret);}}pr_info("@@@@host_store %d, ret = %d\n", chip->is_host, ret);return size;}static DEVICE_ATTR(host, S_IRUGO | S_IWUSR, host_show, host_store);static DEVICE_ATTR(reset, S_IWUSR,NULL, reset_store);static struct device_attribute *usb4604_attributes[] = {&dev_attr_host,&dev_attr_reset,NULL};static int usb4604_parse_dt(struct device *dev,struct usb4604_chip *chip){struct device_node *np = dev->of_node;int ret = 0;/* usbid gpio */ret = of_get_named_gpio_flags(np, "usbid-gpios", 0, NULL);if(ret < 0) {dev_err(dev, "Unable to read usbid gpio. ret = %d\n", ret);return ret;}chip->usbid_gpio = ret;if (!gpio_is_valid(chip->usbid_gpio)) {dev_err(dev,"invalid power pin: %d\n", chip->usbid_gpio);}ret = gpio_request(chip->usbid_gpio, "usbid-gpios");if (ret < 0) {dev_err(dev,"%s: gpio %d request failed. ret = %d\n",__func__, chip->usbid_gpio, ret);return ret;}/* reset gpio */ret = of_get_named_gpio_flags(np, "reset-gpios", 0, NULL);if(ret < 0) {dev_err(dev, "Unable to read reset gpio. ret = %d\n", ret);return ret;}chip->reset_gpio = ret;if (!gpio_is_valid(chip->reset_gpio)) {dev_err(dev,"invalid power pin: %d\n", chip->reset_gpio);}ret = gpio_request(chip->reset_gpio, "usb4604-reset-gpios");if (ret < 0) {dev_err(dev,"%s: gpio %d request failed. ret = %d\n",__func__, chip->reset_gpio, ret);return ret;}return 0;}static int usb4604_probe(struct i2c_client *client,const struct i2c_device_id *id){int ret;struct usb4604_chip *chip;struct device_attribute *attr;struct device_attribute **attrs = usb4604_attributes;pr_info("usb4604_probe\n");chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);if (!chip) {dev_err(&client->dev, "Unable to allocate memory\n");return -ENOMEM;}chip->client = client;dev_set_drvdata(&client->dev, chip);if (client->dev.of_node) {ret = usb4604_parse_dt(&client->dev, chip);if (ret) {dev_err(&client->dev,"%s: usb4604_parse_dt() err\n", __func__);goto err_parse_dt;}} else {dev_err(&client->dev, "No dts data\n");goto err_parse_dt;}while ((attr = *attrs++)) {ret = device_create_file(&client->dev, attr);if (ret)goto err_parse_dt;}//if(tca8418_usb4604_gpio_init() < 0)//pr_info("usb4604 power error\n");return 0;err_parse_dt:devm_kfree(&client->dev,chip);return ret;}static int usb4604_remove(struct i2c_client *client){return 0;}static struct of_device_id usb4604_match_table[] = {{ .compatible = "microchip,usb4604",},{ },};static const struct i2c_device_id usb4604_id[] = {{"usb4604", 0},{},};static struct i2c_driver usb4604_driver = {.driver= {.name= "usb4604",.owner= THIS_MODULE,.of_match_table= usb4604_match_table,},.probe= usb4604_probe,.remove= usb4604_remove,.id_table= usb4604_id,};module_i2c_driver(usb4604_driver);MODULE_DESCRIPTION("usb4604");MODULE_LICENSE("GPL v2");MODULE_ALIAS("i2c:usb4604");

  • 向从机发送信息:

 int i2c_master_send(const struct i2c_client *client, const char *buf, int count) {        int ret;      struct i2c_adapter *adap = client->adapter;     struct i2c_msg msg;      msg.addr = client->addr;     msg.flags = client->flags & I2C_M_TEN;     msg.len = count;     msg.buf = (char *)buf;      ret = i2c_transfer(adap, &msg, 1);      /*      * If everything went ok (i.e. 1 msg transmitted), return #bytes      * transmitted, else error code.      */     return (ret == 1) ? count : ret; }

  • 向从机读取信息:
 int i2c_master_recv(const struct i2c_client *client, char *buf, int count) {     struct i2c_adapter *adap = client->adapter;     struct i2c_msg msg;     int ret;      msg.addr = client->addr;     msg.flags = client->flags & I2C_M_TEN;     msg.flags |= I2C_M_RD;     msg.len = count;     msg.buf = buf;      ret = i2c_transfer(adap, &msg, 1);      /*       * If everything went ok (i.e. 1 msg received), return #bytes received,      * else error code.      */      return (ret == 1) ? count : ret; }    EXPORT_SYMBOL(i2c_master_recv);

可参考文档:http://www.t-firefly.com/doc/product/info/id/90.html#.E9.80.9A.E8.BF.87_I2C_.E6.94.B6.E5.8F.91.E6.95.B0.E6.8D.AE