linux/drivers/i2c/busses/i2c-cbus-gpio.c
<<
>>
Prefs
   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/slab.h>
  23#include <linux/delay.h>
  24#include <linux/errno.h>
  25#include <linux/kernel.h>
  26#include <linux/module.h>
  27#include <linux/of_gpio.h>
  28#include <linux/interrupt.h>
  29#include <linux/platform_device.h>
  30#include <linux/platform_data/i2c-cbus-gpio.h>
  31
  32/*
  33 * Bit counts are derived from Nokia implementation. These should be checked
  34 * if other CBUS implementations appear.
  35 */
  36#define CBUS_ADDR_BITS  3
  37#define CBUS_REG_BITS   5
  38
  39struct cbus_host {
  40        spinlock_t      lock;           /* host lock */
  41        struct device   *dev;
  42        int             clk_gpio;
  43        int             dat_gpio;
  44        int             sel_gpio;
  45};
  46
  47/**
  48 * cbus_send_bit - sends one bit over the bus
  49 * @host: the host we're using
  50 * @bit: one bit of information to send
  51 */
  52static void cbus_send_bit(struct cbus_host *host, unsigned bit)
  53{
  54        gpio_set_value(host->dat_gpio, bit ? 1 : 0);
  55        gpio_set_value(host->clk_gpio, 1);
  56        gpio_set_value(host->clk_gpio, 0);
  57}
  58
  59/**
  60 * cbus_send_data - sends @len amount of data over the bus
  61 * @host: the host we're using
  62 * @data: the data to send
  63 * @len: size of the transfer
  64 */
  65static void cbus_send_data(struct cbus_host *host, unsigned data, unsigned len)
  66{
  67        int i;
  68
  69        for (i = len; i > 0; i--)
  70                cbus_send_bit(host, data & (1 << (i - 1)));
  71}
  72
  73/**
  74 * cbus_receive_bit - receives one bit from the bus
  75 * @host: the host we're using
  76 */
  77static int cbus_receive_bit(struct cbus_host *host)
  78{
  79        int ret;
  80
  81        gpio_set_value(host->clk_gpio, 1);
  82        ret = gpio_get_value(host->dat_gpio);
  83        gpio_set_value(host->clk_gpio, 0);
  84        return ret;
  85}
  86
  87/**
  88 * cbus_receive_word - receives 16-bit word from the bus
  89 * @host: the host we're using
  90 */
  91static int cbus_receive_word(struct cbus_host *host)
  92{
  93        int ret = 0;
  94        int i;
  95
  96        for (i = 16; i > 0; i--) {
  97                int bit = cbus_receive_bit(host);
  98
  99                if (bit < 0)
 100                        return bit;
 101
 102                if (bit)
 103                        ret |= 1 << (i - 1);
 104        }
 105        return ret;
 106}
 107
 108/**
 109 * cbus_transfer - transfers data over the bus
 110 * @host: the host we're using
 111 * @rw: read/write flag
 112 * @dev: device address
 113 * @reg: register address
 114 * @data: if @rw == I2C_SBUS_WRITE data to send otherwise 0
 115 */
 116static int cbus_transfer(struct cbus_host *host, char rw, unsigned dev,
 117                         unsigned reg, unsigned data)
 118{
 119        unsigned long flags;
 120        int ret;
 121
 122        /* We don't want interrupts disturbing our transfer */
 123        spin_lock_irqsave(&host->lock, flags);
 124
 125        /* Reset state and start of transfer, SEL stays down during transfer */
 126        gpio_set_value(host->sel_gpio, 0);
 127
 128        /* Set the DAT pin to output */
 129        gpio_direction_output(host->dat_gpio, 1);
 130
 131        /* Send the device address */
 132        cbus_send_data(host, dev, CBUS_ADDR_BITS);
 133
 134        /* Send the rw flag */
 135        cbus_send_bit(host, rw == I2C_SMBUS_READ);
 136
 137        /* Send the register address */
 138        cbus_send_data(host, reg, CBUS_REG_BITS);
 139
 140        if (rw == I2C_SMBUS_WRITE) {
 141                cbus_send_data(host, data, 16);
 142                ret = 0;
 143        } else {
 144                ret = gpio_direction_input(host->dat_gpio);
 145                if (ret) {
 146                        dev_dbg(host->dev, "failed setting direction\n");
 147                        goto out;
 148                }
 149                gpio_set_value(host->clk_gpio, 1);
 150
 151                ret = cbus_receive_word(host);
 152                if (ret < 0) {
 153                        dev_dbg(host->dev, "failed receiving data\n");
 154                        goto out;
 155                }
 156        }
 157
 158        /* Indicate end of transfer, SEL goes up until next transfer */
 159        gpio_set_value(host->sel_gpio, 1);
 160        gpio_set_value(host->clk_gpio, 1);
 161        gpio_set_value(host->clk_gpio, 0);
 162
 163out:
 164        spin_unlock_irqrestore(&host->lock, flags);
 165
 166        return ret;
 167}
 168
 169static int cbus_i2c_smbus_xfer(struct i2c_adapter       *adapter,
 170                               u16                      addr,
 171                               unsigned short           flags,
 172                               char                     read_write,
 173                               u8                       command,
 174                               int                      size,
 175                               union i2c_smbus_data     *data)
 176{
 177        struct cbus_host *chost = i2c_get_adapdata(adapter);
 178        int ret;
 179
 180        if (size != I2C_SMBUS_WORD_DATA)
 181                return -EINVAL;
 182
 183        ret = cbus_transfer(chost, read_write == I2C_SMBUS_READ, addr,
 184                            command, data->word);
 185        if (ret < 0)
 186                return ret;
 187
 188        if (read_write == I2C_SMBUS_READ)
 189                data->word = ret;
 190
 191        return 0;
 192}
 193
 194static u32 cbus_i2c_func(struct i2c_adapter *adapter)
 195{
 196        return I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
 197}
 198
 199static const struct i2c_algorithm cbus_i2c_algo = {
 200        .smbus_xfer     = cbus_i2c_smbus_xfer,
 201        .functionality  = cbus_i2c_func,
 202};
 203
 204static int cbus_i2c_remove(struct platform_device *pdev)
 205{
 206        struct i2c_adapter *adapter = platform_get_drvdata(pdev);
 207
 208        i2c_del_adapter(adapter);
 209
 210        return 0;
 211}
 212
 213static int cbus_i2c_probe(struct platform_device *pdev)
 214{
 215        struct i2c_adapter *adapter;
 216        struct cbus_host *chost;
 217        int ret;
 218
 219        adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter),
 220                               GFP_KERNEL);
 221        if (!adapter)
 222                return -ENOMEM;
 223
 224        chost = devm_kzalloc(&pdev->dev, sizeof(*chost), GFP_KERNEL);
 225        if (!chost)
 226                return -ENOMEM;
 227
 228        if (pdev->dev.of_node) {
 229                struct device_node *dnode = pdev->dev.of_node;
 230                if (of_gpio_count(dnode) != 3)
 231                        return -ENODEV;
 232                chost->clk_gpio = of_get_gpio(dnode, 0);
 233                chost->dat_gpio = of_get_gpio(dnode, 1);
 234                chost->sel_gpio = of_get_gpio(dnode, 2);
 235        } else if (dev_get_platdata(&pdev->dev)) {
 236                struct i2c_cbus_platform_data *pdata =
 237                        dev_get_platdata(&pdev->dev);
 238                chost->clk_gpio = pdata->clk_gpio;
 239                chost->dat_gpio = pdata->dat_gpio;
 240                chost->sel_gpio = pdata->sel_gpio;
 241        } else {
 242                return -ENODEV;
 243        }
 244
 245        adapter->owner          = THIS_MODULE;
 246        adapter->class          = I2C_CLASS_HWMON;
 247        adapter->dev.parent     = &pdev->dev;
 248        adapter->dev.of_node    = pdev->dev.of_node;
 249        adapter->nr             = pdev->id;
 250        adapter->timeout        = HZ;
 251        adapter->algo           = &cbus_i2c_algo;
 252        strlcpy(adapter->name, "CBUS I2C adapter", sizeof(adapter->name));
 253
 254        spin_lock_init(&chost->lock);
 255        chost->dev = &pdev->dev;
 256
 257        ret = devm_gpio_request_one(&pdev->dev, chost->clk_gpio,
 258                                    GPIOF_OUT_INIT_LOW, "CBUS clk");
 259        if (ret)
 260                return ret;
 261
 262        ret = devm_gpio_request_one(&pdev->dev, chost->dat_gpio, GPIOF_IN,
 263                                    "CBUS data");
 264        if (ret)
 265                return ret;
 266
 267        ret = devm_gpio_request_one(&pdev->dev, chost->sel_gpio,
 268                                    GPIOF_OUT_INIT_HIGH, "CBUS sel");
 269        if (ret)
 270                return ret;
 271
 272        i2c_set_adapdata(adapter, chost);
 273        platform_set_drvdata(pdev, adapter);
 274
 275        return i2c_add_numbered_adapter(adapter);
 276}
 277
 278#if defined(CONFIG_OF)
 279static const struct of_device_id i2c_cbus_dt_ids[] = {
 280        { .compatible = "i2c-cbus-gpio", },
 281        { }
 282};
 283MODULE_DEVICE_TABLE(of, i2c_cbus_dt_ids);
 284#endif
 285
 286static struct platform_driver cbus_i2c_driver = {
 287        .probe  = cbus_i2c_probe,
 288        .remove = cbus_i2c_remove,
 289        .driver = {
 290                .name   = "i2c-cbus-gpio",
 291                .of_match_table = of_match_ptr(i2c_cbus_dt_ids),
 292        },
 293};
 294module_platform_driver(cbus_i2c_driver);
 295
 296MODULE_ALIAS("platform:i2c-cbus-gpio");
 297MODULE_DESCRIPTION("CBUS I2C driver");
 298MODULE_AUTHOR("Juha Yrjölä");
 299MODULE_AUTHOR("David Weinehall");
 300MODULE_AUTHOR("Mikko Ylinen");
 301MODULE_AUTHOR("Felipe Balbi");
 302MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
 303MODULE_LICENSE("GPL");
 304