Commit 0857ba3c24c308f42a242fe8a1894772750230ce

Authored by Aaro Koskinen
Committed by Wolfram Sang
1 parent a000b8c1e3

i2c: i2c-cbus-gpio: introduce driver

Add i2c driver to enable access to devices behind CBUS on Nokia Internet
Tablets.

The patch also adds CBUS I2C configuration for N8x0 which is one of the
users of this driver.

Acked-by: Felipe Balbi <balbi@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>

Showing 6 changed files with 407 additions and 0 deletions Side-by-side Diff

Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt
  1 +Device tree bindings for i2c-cbus-gpio driver
  2 +
  3 +Required properties:
  4 + - compatible = "i2c-cbus-gpio";
  5 + - gpios: clk, dat, sel
  6 + - #address-cells = <1>;
  7 + - #size-cells = <0>;
  8 +
  9 +Optional properties:
  10 + - child nodes conforming to i2c bus binding
  11 +
  12 +Example:
  13 +
  14 +i2c@0 {
  15 + compatible = "i2c-cbus-gpio";
  16 + gpios = <&gpio 66 0 /* clk */
  17 + &gpio 65 0 /* dat */
  18 + &gpio 64 0 /* sel */
  19 + >;
  20 + #address-cells = <1>;
  21 + #size-cells = <0>;
  22 +
  23 + retu-mfd: retu@1 {
  24 + compatible = "retu-mfd";
  25 + reg = <0x1>;
  26 + };
  27 +};
arch/arm/mach-omap2/board-n8x0.c
... ... @@ -16,10 +16,12 @@
16 16 #include <linux/gpio.h>
17 17 #include <linux/init.h>
18 18 #include <linux/io.h>
  19 +#include <linux/irq.h>
19 20 #include <linux/stddef.h>
20 21 #include <linux/i2c.h>
21 22 #include <linux/spi/spi.h>
22 23 #include <linux/usb/musb.h>
  24 +#include <linux/platform_data/i2c-cbus-gpio.h>
23 25 #include <linux/platform_data/spi-omap2-mcspi.h>
24 26 #include <linux/platform_data/mtd-onenand-omap2.h>
25 27 #include <sound/tlv320aic3x.h>
... ... @@ -39,6 +41,45 @@
39 41 #define TUSB6010_GPIO_ENABLE 0
40 42 #define TUSB6010_DMACHAN 0x3f
41 43  
  44 +#if defined(CONFIG_I2C_CBUS_GPIO) || defined(CONFIG_I2C_CBUS_GPIO_MODULE)
  45 +static struct i2c_cbus_platform_data n8x0_cbus_data = {
  46 + .clk_gpio = 66,
  47 + .dat_gpio = 65,
  48 + .sel_gpio = 64,
  49 +};
  50 +
  51 +static struct platform_device n8x0_cbus_device = {
  52 + .name = "i2c-cbus-gpio",
  53 + .id = 3,
  54 + .dev = {
  55 + .platform_data = &n8x0_cbus_data,
  56 + },
  57 +};
  58 +
  59 +static struct i2c_board_info n8x0_i2c_board_info_3[] __initdata = {
  60 + {
  61 + I2C_BOARD_INFO("retu-mfd", 0x01),
  62 + },
  63 +};
  64 +
  65 +static void __init n8x0_cbus_init(void)
  66 +{
  67 + const int retu_irq_gpio = 108;
  68 +
  69 + if (gpio_request_one(retu_irq_gpio, GPIOF_IN, "Retu IRQ"))
  70 + return;
  71 + irq_set_irq_type(gpio_to_irq(retu_irq_gpio), IRQ_TYPE_EDGE_RISING);
  72 + n8x0_i2c_board_info_3[0].irq = gpio_to_irq(retu_irq_gpio);
  73 + i2c_register_board_info(3, n8x0_i2c_board_info_3,
  74 + ARRAY_SIZE(n8x0_i2c_board_info_3));
  75 + platform_device_register(&n8x0_cbus_device);
  76 +}
  77 +#else /* CONFIG_I2C_CBUS_GPIO */
  78 +static void __init n8x0_cbus_init(void)
  79 +{
  80 +}
  81 +#endif /* CONFIG_I2C_CBUS_GPIO */
  82 +
42 83 #if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
43 84 /*
44 85 * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
... ... @@ -677,6 +718,7 @@
677 718 gpmc_onenand_init(board_onenand_data);
678 719 n8x0_mmc_init();
679 720 n8x0_usb_init();
  721 + n8x0_cbus_init();
680 722 }
681 723  
682 724 MACHINE_START(NOKIA_N800, "Nokia N800")
drivers/i2c/busses/Kconfig
... ... @@ -337,6 +337,16 @@
337 337 help
338 338 The unit of the TWI clock is kHz.
339 339  
  340 +config I2C_CBUS_GPIO
  341 + tristate "CBUS I2C driver"
  342 + depends on GENERIC_GPIO
  343 + help
  344 + Support for CBUS access using I2C API. Mostly relevant for Nokia
  345 + Internet Tablets (770, N800 and N810).
  346 +
  347 + This driver can also be built as a module. If so, the module
  348 + will be called i2c-cbus-gpio.
  349 +
340 350 config I2C_CPM
341 351 tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
342 352 depends on (CPM1 || CPM2) && OF_I2C
drivers/i2c/busses/Makefile
... ... @@ -31,6 +31,7 @@
31 31 obj-$(CONFIG_I2C_AT91) += i2c-at91.o
32 32 obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
33 33 obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
  34 +obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
34 35 obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
35 36 obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
36 37 obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
drivers/i2c/busses/i2c-cbus-gpio.c
  1 +/*
  2 + * CBUS I2C driver for Nokia Internet Tablets.
  3 + *
  4 + * Copyright (C) 2004-2010 Nokia Corporation
  5 + *
  6 + * Based on code written by Juha Yrjölä, David Weinehall, Mikko Ylinen and
  7 + * Felipe Balbi. Converted to I2C driver by Aaro Koskinen.
  8 + *
  9 + * This file is subject to the terms and conditions of the GNU General
  10 + * Public License. See the file "COPYING" in the main directory of this
  11 + * archive for more details.
  12 + *
  13 + * This program is distributed in the hope that it will be useful,
  14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + * GNU General Public License for more details.
  17 + */
  18 +
  19 +#include <linux/io.h>
  20 +#include <linux/i2c.h>
  21 +#include <linux/gpio.h>
  22 +#include <linux/init.h>
  23 +#include <linux/slab.h>
  24 +#include <linux/delay.h>
  25 +#include <linux/errno.h>
  26 +#include <linux/kernel.h>
  27 +#include <linux/module.h>
  28 +#include <linux/of_gpio.h>
  29 +#include <linux/interrupt.h>
  30 +#include <linux/platform_device.h>
  31 +#include <linux/platform_data/i2c-cbus-gpio.h>
  32 +
  33 +/*
  34 + * Bit counts are derived from Nokia implementation. These should be checked
  35 + * if other CBUS implementations appear.
  36 + */
  37 +#define CBUS_ADDR_BITS 3
  38 +#define CBUS_REG_BITS 5
  39 +
  40 +struct cbus_host {
  41 + spinlock_t lock; /* host lock */
  42 + struct device *dev;
  43 + int clk_gpio;
  44 + int dat_gpio;
  45 + int sel_gpio;
  46 +};
  47 +
  48 +/**
  49 + * cbus_send_bit - sends one bit over the bus
  50 + * @host: the host we're using
  51 + * @bit: one bit of information to send
  52 + */
  53 +static void cbus_send_bit(struct cbus_host *host, unsigned bit)
  54 +{
  55 + gpio_set_value(host->dat_gpio, bit ? 1 : 0);
  56 + gpio_set_value(host->clk_gpio, 1);
  57 + gpio_set_value(host->clk_gpio, 0);
  58 +}
  59 +
  60 +/**
  61 + * cbus_send_data - sends @len amount of data over the bus
  62 + * @host: the host we're using
  63 + * @data: the data to send
  64 + * @len: size of the transfer
  65 + */
  66 +static void cbus_send_data(struct cbus_host *host, unsigned data, unsigned len)
  67 +{
  68 + int i;
  69 +
  70 + for (i = len; i > 0; i--)
  71 + cbus_send_bit(host, data & (1 << (i - 1)));
  72 +}
  73 +
  74 +/**
  75 + * cbus_receive_bit - receives one bit from the bus
  76 + * @host: the host we're using
  77 + */
  78 +static int cbus_receive_bit(struct cbus_host *host)
  79 +{
  80 + int ret;
  81 +
  82 + gpio_set_value(host->clk_gpio, 1);
  83 + ret = gpio_get_value(host->dat_gpio);
  84 + gpio_set_value(host->clk_gpio, 0);
  85 + return ret;
  86 +}
  87 +
  88 +/**
  89 + * cbus_receive_word - receives 16-bit word from the bus
  90 + * @host: the host we're using
  91 + */
  92 +static int cbus_receive_word(struct cbus_host *host)
  93 +{
  94 + int ret = 0;
  95 + int i;
  96 +
  97 + for (i = 16; i > 0; i--) {
  98 + int bit = cbus_receive_bit(host);
  99 +
  100 + if (bit < 0)
  101 + return bit;
  102 +
  103 + if (bit)
  104 + ret |= 1 << (i - 1);
  105 + }
  106 + return ret;
  107 +}
  108 +
  109 +/**
  110 + * cbus_transfer - transfers data over the bus
  111 + * @host: the host we're using
  112 + * @rw: read/write flag
  113 + * @dev: device address
  114 + * @reg: register address
  115 + * @data: if @rw == I2C_SBUS_WRITE data to send otherwise 0
  116 + */
  117 +static int cbus_transfer(struct cbus_host *host, char rw, unsigned dev,
  118 + unsigned reg, unsigned data)
  119 +{
  120 + unsigned long flags;
  121 + int ret;
  122 +
  123 + /* We don't want interrupts disturbing our transfer */
  124 + spin_lock_irqsave(&host->lock, flags);
  125 +
  126 + /* Reset state and start of transfer, SEL stays down during transfer */
  127 + gpio_set_value(host->sel_gpio, 0);
  128 +
  129 + /* Set the DAT pin to output */
  130 + gpio_direction_output(host->dat_gpio, 1);
  131 +
  132 + /* Send the device address */
  133 + cbus_send_data(host, dev, CBUS_ADDR_BITS);
  134 +
  135 + /* Send the rw flag */
  136 + cbus_send_bit(host, rw == I2C_SMBUS_READ);
  137 +
  138 + /* Send the register address */
  139 + cbus_send_data(host, reg, CBUS_REG_BITS);
  140 +
  141 + if (rw == I2C_SMBUS_WRITE) {
  142 + cbus_send_data(host, data, 16);
  143 + ret = 0;
  144 + } else {
  145 + ret = gpio_direction_input(host->dat_gpio);
  146 + if (ret) {
  147 + dev_dbg(host->dev, "failed setting direction\n");
  148 + goto out;
  149 + }
  150 + gpio_set_value(host->clk_gpio, 1);
  151 +
  152 + ret = cbus_receive_word(host);
  153 + if (ret < 0) {
  154 + dev_dbg(host->dev, "failed receiving data\n");
  155 + goto out;
  156 + }
  157 + }
  158 +
  159 + /* Indicate end of transfer, SEL goes up until next transfer */
  160 + gpio_set_value(host->sel_gpio, 1);
  161 + gpio_set_value(host->clk_gpio, 1);
  162 + gpio_set_value(host->clk_gpio, 0);
  163 +
  164 +out:
  165 + spin_unlock_irqrestore(&host->lock, flags);
  166 +
  167 + return ret;
  168 +}
  169 +
  170 +static int cbus_i2c_smbus_xfer(struct i2c_adapter *adapter,
  171 + u16 addr,
  172 + unsigned short flags,
  173 + char read_write,
  174 + u8 command,
  175 + int size,
  176 + union i2c_smbus_data *data)
  177 +{
  178 + struct cbus_host *chost = i2c_get_adapdata(adapter);
  179 + int ret;
  180 +
  181 + if (size != I2C_SMBUS_WORD_DATA)
  182 + return -EINVAL;
  183 +
  184 + ret = cbus_transfer(chost, read_write == I2C_SMBUS_READ, addr,
  185 + command, data->word);
  186 + if (ret < 0)
  187 + return ret;
  188 +
  189 + if (read_write == I2C_SMBUS_READ)
  190 + data->word = ret;
  191 +
  192 + return 0;
  193 +}
  194 +
  195 +static u32 cbus_i2c_func(struct i2c_adapter *adapter)
  196 +{
  197 + return I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
  198 +}
  199 +
  200 +static const struct i2c_algorithm cbus_i2c_algo = {
  201 + .smbus_xfer = cbus_i2c_smbus_xfer,
  202 + .functionality = cbus_i2c_func,
  203 +};
  204 +
  205 +static int cbus_i2c_remove(struct platform_device *pdev)
  206 +{
  207 + struct i2c_adapter *adapter = platform_get_drvdata(pdev);
  208 +
  209 + return i2c_del_adapter(adapter);
  210 +}
  211 +
  212 +static int cbus_i2c_probe(struct platform_device *pdev)
  213 +{
  214 + struct i2c_adapter *adapter;
  215 + struct cbus_host *chost;
  216 + int ret;
  217 +
  218 + adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter),
  219 + GFP_KERNEL);
  220 + if (!adapter)
  221 + return -ENOMEM;
  222 +
  223 + chost = devm_kzalloc(&pdev->dev, sizeof(*chost), GFP_KERNEL);
  224 + if (!chost)
  225 + return -ENOMEM;
  226 +
  227 + if (pdev->dev.of_node) {
  228 + struct device_node *dnode = pdev->dev.of_node;
  229 + if (of_gpio_count(dnode) != 3)
  230 + return -ENODEV;
  231 + chost->clk_gpio = of_get_gpio(dnode, 0);
  232 + chost->dat_gpio = of_get_gpio(dnode, 1);
  233 + chost->sel_gpio = of_get_gpio(dnode, 2);
  234 + } else if (pdev->dev.platform_data) {
  235 + struct i2c_cbus_platform_data *pdata = pdev->dev.platform_data;
  236 + chost->clk_gpio = pdata->clk_gpio;
  237 + chost->dat_gpio = pdata->dat_gpio;
  238 + chost->sel_gpio = pdata->sel_gpio;
  239 + } else {
  240 + return -ENODEV;
  241 + }
  242 +
  243 + adapter->owner = THIS_MODULE;
  244 + adapter->class = I2C_CLASS_HWMON;
  245 + adapter->dev.parent = &pdev->dev;
  246 + adapter->nr = pdev->id;
  247 + adapter->timeout = HZ;
  248 + adapter->algo = &cbus_i2c_algo;
  249 + strlcpy(adapter->name, "CBUS I2C adapter", sizeof(adapter->name));
  250 +
  251 + spin_lock_init(&chost->lock);
  252 + chost->dev = &pdev->dev;
  253 +
  254 + ret = devm_gpio_request_one(&pdev->dev, chost->clk_gpio,
  255 + GPIOF_OUT_INIT_LOW, "CBUS clk");
  256 + if (ret)
  257 + return ret;
  258 +
  259 + ret = devm_gpio_request_one(&pdev->dev, chost->dat_gpio, GPIOF_IN,
  260 + "CBUS data");
  261 + if (ret)
  262 + return ret;
  263 +
  264 + ret = devm_gpio_request_one(&pdev->dev, chost->sel_gpio,
  265 + GPIOF_OUT_INIT_HIGH, "CBUS sel");
  266 + if (ret)
  267 + return ret;
  268 +
  269 + i2c_set_adapdata(adapter, chost);
  270 + platform_set_drvdata(pdev, adapter);
  271 +
  272 + return i2c_add_numbered_adapter(adapter);
  273 +}
  274 +
  275 +#if defined(CONFIG_OF)
  276 +static const struct of_device_id i2c_cbus_dt_ids[] = {
  277 + { .compatible = "i2c-cbus-gpio", },
  278 + { }
  279 +};
  280 +MODULE_DEVICE_TABLE(of, i2c_cbus_dt_ids);
  281 +#endif
  282 +
  283 +static struct platform_driver cbus_i2c_driver = {
  284 + .probe = cbus_i2c_probe,
  285 + .remove = cbus_i2c_remove,
  286 + .driver = {
  287 + .owner = THIS_MODULE,
  288 + .name = "i2c-cbus-gpio",
  289 + },
  290 +};
  291 +module_platform_driver(cbus_i2c_driver);
  292 +
  293 +MODULE_ALIAS("platform:i2c-cbus-gpio");
  294 +MODULE_DESCRIPTION("CBUS I2C driver");
  295 +MODULE_AUTHOR("Juha Yrjölä");
  296 +MODULE_AUTHOR("David Weinehall");
  297 +MODULE_AUTHOR("Mikko Ylinen");
  298 +MODULE_AUTHOR("Felipe Balbi");
  299 +MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
  300 +MODULE_LICENSE("GPL");
include/linux/platform_data/i2c-cbus-gpio.h
  1 +/*
  2 + * i2c-cbus-gpio.h - CBUS I2C platform_data definition
  3 + *
  4 + * Copyright (C) 2004-2009 Nokia Corporation
  5 + *
  6 + * Written by Felipe Balbi and Aaro Koskinen.
  7 + *
  8 + * This file is subject to the terms and conditions of the GNU General
  9 + * Public License. See the file "COPYING" in the main directory of this
  10 + * archive for more details.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + */
  17 +
  18 +#ifndef __INCLUDE_LINUX_I2C_CBUS_GPIO_H
  19 +#define __INCLUDE_LINUX_I2C_CBUS_GPIO_H
  20 +
  21 +struct i2c_cbus_platform_data {
  22 + int dat_gpio;
  23 + int clk_gpio;
  24 + int sel_gpio;
  25 +};
  26 +
  27 +#endif /* __INCLUDE_LINUX_I2C_CBUS_GPIO_H */