您的位置:首页 > 其它

简单i2c设备驱动实例

2017-12-29 14:04 555 查看
原址

平台: msm8916

OS:安卓5.1

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

设备树文件如下:

[cpp] view
plain copy

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对应的寄存器写入对应的值。

[cpp] view
plain copy

/* 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);  

            }  

        else  

            mdelay(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)enable  

    for(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);  

            }  

        }  

    else  

        pr_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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: