简单i2c设备驱动实例

  相关文章:

                 一 .   i2c总线协议

                 二.   普通IO模拟i2c总线

                 三.   简单i2c设备驱动实例

平台: msm8916

OS:安卓5.1

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

 

设备树文件如下:

   microchip@2d {
			compatible = "microchip,usb4604"; //驱动根据这个来匹配,然后调用prob函数,调试可在prob增加打印
						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);
			}
		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_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);
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);

可参考文档:参考文档地址

 

 

 

 

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kevin@1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值