linux/drivers/i2c/busses/i2c-kempld.c
<<
>>
Prefs
   1/*
   2 * I2C bus driver for Kontron COM modules
   3 *
   4 * Copyright (c) 2010-2013 Kontron Europe GmbH
   5 * Author: Michael Brunner <michael.brunner@kontron.com>
   6 *
   7 * The driver is based on the i2c-ocores driver by Peter Korsgaard.
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License 2 as published
  11 * by the Free Software Foundation.
  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/module.h>
  20#include <linux/platform_device.h>
  21#include <linux/i2c.h>
  22#include <linux/delay.h>
  23#include <linux/mfd/kempld.h>
  24
  25#define KEMPLD_I2C_PRELOW       0x0b
  26#define KEMPLD_I2C_PREHIGH      0x0c
  27#define KEMPLD_I2C_DATA         0x0e
  28
  29#define KEMPLD_I2C_CTRL         0x0d
  30#define I2C_CTRL_IEN            0x40
  31#define I2C_CTRL_EN             0x80
  32
  33#define KEMPLD_I2C_STAT         0x0f
  34#define I2C_STAT_IF             0x01
  35#define I2C_STAT_TIP            0x02
  36#define I2C_STAT_ARBLOST        0x20
  37#define I2C_STAT_BUSY           0x40
  38#define I2C_STAT_NACK           0x80
  39
  40#define KEMPLD_I2C_CMD          0x0f
  41#define I2C_CMD_START           0x91
  42#define I2C_CMD_STOP            0x41
  43#define I2C_CMD_READ            0x21
  44#define I2C_CMD_WRITE           0x11
  45#define I2C_CMD_READ_ACK        0x21
  46#define I2C_CMD_READ_NACK       0x29
  47#define I2C_CMD_IACK            0x01
  48
  49#define KEMPLD_I2C_FREQ_MAX     2700    /* 2.7 mHz */
  50#define KEMPLD_I2C_FREQ_STD     100     /* 100 kHz */
  51
  52enum {
  53        STATE_DONE = 0,
  54        STATE_INIT,
  55        STATE_ADDR,
  56        STATE_ADDR10,
  57        STATE_START,
  58        STATE_WRITE,
  59        STATE_READ,
  60        STATE_ERROR,
  61};
  62
  63struct kempld_i2c_data {
  64        struct device                   *dev;
  65        struct kempld_device_data       *pld;
  66        struct i2c_adapter              adap;
  67        struct i2c_msg                  *msg;
  68        int                             pos;
  69        int                             nmsgs;
  70        int                             state;
  71        bool                            was_active;
  72};
  73
  74static unsigned int bus_frequency = KEMPLD_I2C_FREQ_STD;
  75module_param(bus_frequency, uint, 0);
  76MODULE_PARM_DESC(bus_frequency, "Set I2C bus frequency in kHz (default="
  77                                __MODULE_STRING(KEMPLD_I2C_FREQ_STD)")");
  78
  79static int i2c_bus = -1;
  80module_param(i2c_bus, int, 0);
  81MODULE_PARM_DESC(i2c_bus, "Set I2C bus number (default=-1 for dynamic assignment)");
  82
  83static bool i2c_gpio_mux;
  84module_param(i2c_gpio_mux, bool, 0);
  85MODULE_PARM_DESC(i2c_gpio_mux, "Enable I2C port on GPIO out (default=false)");
  86
  87/*
  88 * kempld_get_mutex must be called prior to calling this function.
  89 */
  90static int kempld_i2c_process(struct kempld_i2c_data *i2c)
  91{
  92        struct kempld_device_data *pld = i2c->pld;
  93        u8 stat = kempld_read8(pld, KEMPLD_I2C_STAT);
  94        struct i2c_msg *msg = i2c->msg;
  95        u8 addr;
  96
  97        /* Ready? */
  98        if (stat & I2C_STAT_TIP)
  99                return -EBUSY;
 100
 101        if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {
 102                /* Stop has been sent */
 103                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK);
 104                if (i2c->state == STATE_ERROR)
 105                        return -EIO;
 106                return 0;
 107        }
 108
 109        /* Error? */
 110        if (stat & I2C_STAT_ARBLOST) {
 111                i2c->state = STATE_ERROR;
 112                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
 113                return -EAGAIN;
 114        }
 115
 116        if (i2c->state == STATE_INIT) {
 117                if (stat & I2C_STAT_BUSY)
 118                        return -EBUSY;
 119
 120                i2c->state = STATE_ADDR;
 121        }
 122
 123        if (i2c->state == STATE_ADDR) {
 124                /* 10 bit address? */
 125                if (i2c->msg->flags & I2C_M_TEN) {
 126                        addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6);
 127                        /* Set read bit if necessary */
 128                        addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
 129                        i2c->state = STATE_ADDR10;
 130                } else {
 131                        addr = i2c_8bit_addr_from_msg(i2c->msg);
 132                        i2c->state = STATE_START;
 133                }
 134
 135                kempld_write8(pld, KEMPLD_I2C_DATA, addr);
 136                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_START);
 137
 138                return 0;
 139        }
 140
 141        /* Second part of 10 bit addressing */
 142        if (i2c->state == STATE_ADDR10) {
 143                kempld_write8(pld, KEMPLD_I2C_DATA, i2c->msg->addr & 0xff);
 144                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
 145
 146                i2c->state = STATE_START;
 147                return 0;
 148        }
 149
 150        if (i2c->state == STATE_START || i2c->state == STATE_WRITE) {
 151                i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
 152
 153                if (stat & I2C_STAT_NACK) {
 154                        i2c->state = STATE_ERROR;
 155                        kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
 156                        return -ENXIO;
 157                }
 158        } else {
 159                msg->buf[i2c->pos++] = kempld_read8(pld, KEMPLD_I2C_DATA);
 160        }
 161
 162        if (i2c->pos >= msg->len) {
 163                i2c->nmsgs--;
 164                i2c->msg++;
 165                i2c->pos = 0;
 166                msg = i2c->msg;
 167
 168                if (i2c->nmsgs) {
 169                        if (!(msg->flags & I2C_M_NOSTART)) {
 170                                i2c->state = STATE_ADDR;
 171                                return 0;
 172                        } else {
 173                                i2c->state = (msg->flags & I2C_M_RD)
 174                                        ? STATE_READ : STATE_WRITE;
 175                        }
 176                } else {
 177                        i2c->state = STATE_DONE;
 178                        kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
 179                        return 0;
 180                }
 181        }
 182
 183        if (i2c->state == STATE_READ) {
 184                kempld_write8(pld, KEMPLD_I2C_CMD, i2c->pos == (msg->len - 1) ?
 185                              I2C_CMD_READ_NACK : I2C_CMD_READ_ACK);
 186        } else {
 187                kempld_write8(pld, KEMPLD_I2C_DATA, msg->buf[i2c->pos++]);
 188                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
 189        }
 190
 191        return 0;
 192}
 193
 194static int kempld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 195                                int num)
 196{
 197        struct kempld_i2c_data *i2c = i2c_get_adapdata(adap);
 198        struct kempld_device_data *pld = i2c->pld;
 199        unsigned long timeout = jiffies + HZ;
 200        int ret;
 201
 202        i2c->msg = msgs;
 203        i2c->pos = 0;
 204        i2c->nmsgs = num;
 205        i2c->state = STATE_INIT;
 206
 207        /* Handle the transfer */
 208        while (time_before(jiffies, timeout)) {
 209                kempld_get_mutex(pld);
 210                ret = kempld_i2c_process(i2c);
 211                kempld_release_mutex(pld);
 212
 213                if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR)
 214                        return (i2c->state == STATE_DONE) ? num : ret;
 215
 216                if (ret == 0)
 217                        timeout = jiffies + HZ;
 218
 219                usleep_range(5, 15);
 220        }
 221
 222        i2c->state = STATE_ERROR;
 223
 224        return -ETIMEDOUT;
 225}
 226
 227/*
 228 * kempld_get_mutex must be called prior to calling this function.
 229 */
 230static void kempld_i2c_device_init(struct kempld_i2c_data *i2c)
 231{
 232        struct kempld_device_data *pld = i2c->pld;
 233        u16 prescale_corr;
 234        long prescale;
 235        u8 ctrl;
 236        u8 stat;
 237        u8 cfg;
 238
 239        /* Make sure the device is disabled */
 240        ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
 241        ctrl &= ~(I2C_CTRL_EN | I2C_CTRL_IEN);
 242        kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
 243
 244        if (bus_frequency > KEMPLD_I2C_FREQ_MAX)
 245                bus_frequency = KEMPLD_I2C_FREQ_MAX;
 246
 247        if (pld->info.spec_major == 1)
 248                prescale = pld->pld_clock / (bus_frequency * 5) - 1000;
 249        else
 250                prescale = pld->pld_clock / (bus_frequency * 4) - 3000;
 251
 252        if (prescale < 0)
 253                prescale = 0;
 254
 255        /* Round to the best matching value */
 256        prescale_corr = prescale / 1000;
 257        if (prescale % 1000 >= 500)
 258                prescale_corr++;
 259
 260        kempld_write8(pld, KEMPLD_I2C_PRELOW, prescale_corr & 0xff);
 261        kempld_write8(pld, KEMPLD_I2C_PREHIGH, prescale_corr >> 8);
 262
 263        /* Activate I2C bus output on GPIO pins */
 264        cfg = kempld_read8(pld, KEMPLD_CFG);
 265        if (i2c_gpio_mux)
 266                cfg |= KEMPLD_CFG_GPIO_I2C_MUX;
 267        else
 268                cfg &= ~KEMPLD_CFG_GPIO_I2C_MUX;
 269        kempld_write8(pld, KEMPLD_CFG, cfg);
 270
 271        /* Enable the device */
 272        kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK);
 273        ctrl |= I2C_CTRL_EN;
 274        kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
 275
 276        stat = kempld_read8(pld, KEMPLD_I2C_STAT);
 277        if (stat & I2C_STAT_BUSY)
 278                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
 279}
 280
 281static u32 kempld_i2c_func(struct i2c_adapter *adap)
 282{
 283        return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
 284}
 285
 286static const struct i2c_algorithm kempld_i2c_algorithm = {
 287        .master_xfer    = kempld_i2c_xfer,
 288        .functionality  = kempld_i2c_func,
 289};
 290
 291static const struct i2c_adapter kempld_i2c_adapter = {
 292        .owner          = THIS_MODULE,
 293        .name           = "i2c-kempld",
 294        .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
 295        .algo           = &kempld_i2c_algorithm,
 296};
 297
 298static int kempld_i2c_probe(struct platform_device *pdev)
 299{
 300        struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
 301        struct kempld_i2c_data *i2c;
 302        int ret;
 303        u8 ctrl;
 304
 305        i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
 306        if (!i2c)
 307                return -ENOMEM;
 308
 309        i2c->pld = pld;
 310        i2c->dev = &pdev->dev;
 311        i2c->adap = kempld_i2c_adapter;
 312        i2c->adap.dev.parent = i2c->dev;
 313        i2c_set_adapdata(&i2c->adap, i2c);
 314        platform_set_drvdata(pdev, i2c);
 315
 316        kempld_get_mutex(pld);
 317        ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
 318
 319        if (ctrl & I2C_CTRL_EN)
 320                i2c->was_active = true;
 321
 322        kempld_i2c_device_init(i2c);
 323        kempld_release_mutex(pld);
 324
 325        /* Add I2C adapter to I2C tree */
 326        if (i2c_bus >= -1)
 327                i2c->adap.nr = i2c_bus;
 328        ret = i2c_add_numbered_adapter(&i2c->adap);
 329        if (ret)
 330                return ret;
 331
 332        dev_info(i2c->dev, "I2C bus initialized at %dkHz\n",
 333                 bus_frequency);
 334
 335        return 0;
 336}
 337
 338static int kempld_i2c_remove(struct platform_device *pdev)
 339{
 340        struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
 341        struct kempld_device_data *pld = i2c->pld;
 342        u8 ctrl;
 343
 344        kempld_get_mutex(pld);
 345        /*
 346         * Disable I2C logic if it was not activated before the
 347         * driver loaded
 348         */
 349        if (!i2c->was_active) {
 350                ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
 351                ctrl &= ~I2C_CTRL_EN;
 352                kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
 353        }
 354        kempld_release_mutex(pld);
 355
 356        i2c_del_adapter(&i2c->adap);
 357
 358        return 0;
 359}
 360
 361#ifdef CONFIG_PM
 362static int kempld_i2c_suspend(struct platform_device *pdev, pm_message_t state)
 363{
 364        struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
 365        struct kempld_device_data *pld = i2c->pld;
 366        u8 ctrl;
 367
 368        kempld_get_mutex(pld);
 369        ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
 370        ctrl &= ~I2C_CTRL_EN;
 371        kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
 372        kempld_release_mutex(pld);
 373
 374        return 0;
 375}
 376
 377static int kempld_i2c_resume(struct platform_device *pdev)
 378{
 379        struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
 380        struct kempld_device_data *pld = i2c->pld;
 381
 382        kempld_get_mutex(pld);
 383        kempld_i2c_device_init(i2c);
 384        kempld_release_mutex(pld);
 385
 386        return 0;
 387}
 388#else
 389#define kempld_i2c_suspend      NULL
 390#define kempld_i2c_resume       NULL
 391#endif
 392
 393static struct platform_driver kempld_i2c_driver = {
 394        .driver = {
 395                .name = "kempld-i2c",
 396        },
 397        .probe          = kempld_i2c_probe,
 398        .remove         = kempld_i2c_remove,
 399        .suspend        = kempld_i2c_suspend,
 400        .resume         = kempld_i2c_resume,
 401};
 402
 403module_platform_driver(kempld_i2c_driver);
 404
 405MODULE_DESCRIPTION("KEM PLD I2C Driver");
 406MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
 407MODULE_LICENSE("GPL");
 408MODULE_ALIAS("platform:kempld_i2c");
 409