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