単純i 2 cデバイス駆動例


関連記事:
一.i 2 cバスプロトコル
二.一般IOシミュレーションi 2 cバス
三.単純i 2 cデバイス駆動例
プラットフォーム:msm 8916
OS:アンドロイド5.1
usb 4604は、デバイス上で、デバイスのプライマリ・スレーブ・モードを切り替える役割を果たす.
 
デバイスツリーファイルは次のとおりです.
   microchip@2d {
			compatible = "microchip,usb4604"; //         ,    prob  ,    prob    
						reg = <0x2d>;
                        usbid-gpios = ;
                        reset-gpios = ;
            };

usb 4604ドライバファイル:
sys/bus/i 2 c/devices/0-002 d/hostノードを生成し、echo 0>sys/bus/i 2 c/devices/0-002 d/hostまたはecho 1>sys/bus/i 2 c/devices/0-002 d/hostによってマスターを切り替えることができ、すなわちusb 4604に対応するレジスタに対応する値を書き込むことができる.
/* 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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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
", __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
", __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
", 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
", 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
", __func__, chip->is_host, ret); } } else pr_err("@@@@usb4604_switch I2C ERROR
"); 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
", 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
"); return size; } if (!!host != chip->is_host) { chip->is_host = !!host; ret = usb4604_switch(chip); pr_info("@@@@host_store %d, ret = %d
", 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
"); 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
", __func__, chip->reset_gpio, ret); } } pr_info("@@@@host_store %d, ret = %d
", 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
", ret); return ret; } chip->usbid_gpio = ret; if (!gpio_is_valid(chip->usbid_gpio)) { dev_err(dev, "invalid power pin: %d
", chip->usbid_gpio); } ret = gpio_request(chip->usbid_gpio, "usbid-gpios"); if (ret < 0) { dev_err(dev, "%s: gpio %d request failed. ret = %d
", __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
", ret); return ret; } chip->reset_gpio = ret; if (!gpio_is_valid(chip->reset_gpio)) { dev_err(dev, "invalid power pin: %d
", 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
", __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
"); chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) { dev_err(&client->dev, "Unable to allocate memory
"); 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
", __func__); goto err_parse_dt; } } else { dev_err(&client->dev, "No dts data
"); 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
"); 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);

    参照可能ドキュメント:参照ドキュメントアドレス