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                        i2c->state = STATE_ADDR10;
 128                } else {
 129                        addr = (i2c->msg->addr << 1);
 130                        i2c->state = STATE_START;
 131                }
 132
 133                /* Set read bit if necessary */
 134                addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
 135
 136                kempld_write8(pld, KEMPLD_I2C_DATA, addr);
 137                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_START);
 138
 139                return 0;
 140        }
 141
 142        /* Second part of 10 bit addressing */
 143        if (i2c->state == STATE_ADDR10) {
 144                kempld_write8(pld, KEMPLD_I2C_DATA, i2c->msg->addr & 0xff);
 145                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
 146
 147                i2c->state = STATE_START;
 148                return 0;
 149        }
 150
 151        if (i2c->state == STATE_START || i2c->state == STATE_WRITE) {
 152                i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
 153
 154                if (stat & I2C_STAT_NACK) {
 155                        i2c->state = STATE_ERROR;
 156                        kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
 157                        return -ENXIO;
 158                }
 159        } else {
 160                msg->buf[i2c->pos++] = kempld_read8(pld, KEMPLD_I2C_DATA);
 161        }
 162
 163        if (i2c->pos >= msg->len) {
 164                i2c->nmsgs--;
 165                i2c->msg++;
 166                i2c->pos = 0;
 167                msg = i2c->msg;
 168
 169                if (i2c->nmsgs) {
 170                        if (!(msg->flags & I2C_M_NOSTART)) {
 171                                i2c->state = STATE_ADDR;
 172                                return 0;
 173                        } else {
 174                                i2c->state = (msg->flags & I2C_M_RD)
 175                                        ? STATE_READ : STATE_WRITE;
 176                        }
 177                } else {
 178                        i2c->state = STATE_DONE;
 179                        kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
 180                        return 0;
 181                }
 182        }
 183
 184        if (i2c->state == STATE_READ) {
 185                kempld_write8(pld, KEMPLD_I2C_CMD, i2c->pos == (msg->len - 1) ?
 186                              I2C_CMD_READ_NACK : I2C_CMD_READ_ACK);
 187        } else {
 188                kempld_write8(pld, KEMPLD_I2C_DATA, msg->buf[i2c->pos++]);
 189                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
 190        }
 191
 192        return 0;
 193}
 194
 195static int kempld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 196                                int num)
 197{
 198        struct kempld_i2c_data *i2c = i2c_get_adapdata(adap);
 199        struct kempld_device_data *pld = i2c->pld;
 200        unsigned long timeout = jiffies + HZ;
 201        int ret;
 202
 203        i2c->msg = msgs;
 204        i2c->pos = 0;
 205        i2c->nmsgs = num;
 206        i2c->state = STATE_INIT;
 207
 208        /* Handle the transfer */
 209        while (time_before(jiffies, timeout)) {
 210                kempld_get_mutex(pld);
 211                ret = kempld_i2c_process(i2c);
 212                kempld_release_mutex(pld);
 213
 214                if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR)
 215                        return (i2c->state == STATE_DONE) ? num : ret;
 216
 217                if (ret == 0)
 218                        timeout = jiffies + HZ;
 219
 220                usleep_range(5, 15);
 221        }
 222
 223        i2c->state = STATE_ERROR;
 224
 225        return -ETIMEDOUT;
 226}
 227
 228/*
 229 * kempld_get_mutex must be called prior to calling this function.
 230 */
 231static void kempld_i2c_device_init(struct kempld_i2c_data *i2c)
 232{
 233        struct kempld_device_data *pld = i2c->pld;
 234        u16 prescale_corr;
 235        long prescale;
 236        u8 ctrl;
 237        u8 stat;
 238        u8 cfg;
 239
 240        /* Make sure the device is disabled */
 241        ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
 242        ctrl &= ~(I2C_CTRL_EN | I2C_CTRL_IEN);
 243        kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
 244
 245        if (bus_frequency > KEMPLD_I2C_FREQ_MAX)
 246                bus_frequency = KEMPLD_I2C_FREQ_MAX;
 247
 248        if (pld->info.spec_major == 1)
 249                prescale = pld->pld_clock / (bus_frequency * 5) - 1000;
 250        else
 251                prescale = pld->pld_clock / (bus_frequency * 4) - 3000;
 252
 253        if (prescale < 0)
 254                prescale = 0;
 255
 256        /* Round to the best matching value */
 257        prescale_corr = prescale / 1000;
 258        if (prescale % 1000 >= 500)
 259                prescale_corr++;
 260
 261        kempld_write8(pld, KEMPLD_I2C_PRELOW, prescale_corr & 0xff);
 262        kempld_write8(pld, KEMPLD_I2C_PREHIGH, prescale_corr >> 8);
 263
 264        /* Activate I2C bus output on GPIO pins */
 265        cfg = kempld_read8(pld, KEMPLD_CFG);
 266        if (i2c_gpio_mux)
 267                cfg |= KEMPLD_CFG_GPIO_I2C_MUX;
 268        else
 269                cfg &= ~KEMPLD_CFG_GPIO_I2C_MUX;
 270        kempld_write8(pld, KEMPLD_CFG, cfg);
 271
 272        /* Enable the device */
 273        kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK);
 274        ctrl |= I2C_CTRL_EN;
 275        kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
 276
 277        stat = kempld_read8(pld, KEMPLD_I2C_STAT);
 278        if (stat & I2C_STAT_BUSY)
 279                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
 280}
 281
 282static u32 kempld_i2c_func(struct i2c_adapter *adap)
 283{
 284        return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
 285}
 286
 287static const struct i2c_algorithm kempld_i2c_algorithm = {
 288        .master_xfer    = kempld_i2c_xfer,
 289        .functionality  = kempld_i2c_func,
 290};
 291
 292static struct i2c_adapter kempld_i2c_adapter = {
 293        .owner          = THIS_MODULE,
 294        .name           = "i2c-kempld",
 295        .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
 296        .algo           = &kempld_i2c_algorithm,
 297};
 298
 299static int kempld_i2c_probe(struct platform_device *pdev)
 300{
 301        struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
 302        struct kempld_i2c_data *i2c;
 303        int ret;
 304        u8 ctrl;
 305
 306        i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
 307        if (!i2c)
 308                return -ENOMEM;
 309
 310        i2c->pld = pld;
 311        i2c->dev = &pdev->dev;
 312        i2c->adap = kempld_i2c_adapter;
 313        i2c->adap.dev.parent = i2c->dev;
 314        i2c_set_adapdata(&i2c->adap, i2c);
 315        platform_set_drvdata(pdev, i2c);
 316
 317        kempld_get_mutex(pld);
 318        ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
 319
 320        if (ctrl & I2C_CTRL_EN)
 321                i2c->was_active = true;
 322
 323        kempld_i2c_device_init(i2c);
 324        kempld_release_mutex(pld);
 325
 326        /* Add I2C adapter to I2C tree */
 327        if (i2c_bus >= -1)
 328                i2c->adap.nr = i2c_bus;
 329        ret = i2c_add_numbered_adapter(&i2c->adap);
 330        if (ret)
 331                return ret;
 332
 333        dev_info(i2c->dev, "I2C bus initialized at %dkHz\n",
 334                 bus_frequency);
 335
 336        return 0;
 337}
 338
 339static int kempld_i2c_remove(struct platform_device *pdev)
 340{
 341        struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
 342        struct kempld_device_data *pld = i2c->pld;
 343        u8 ctrl;
 344
 345        kempld_get_mutex(pld);
 346        /*
 347         * Disable I2C logic if it was not activated before the
 348         * driver loaded
 349         */
 350        if (!i2c->was_active) {
 351                ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
 352                ctrl &= ~I2C_CTRL_EN;
 353                kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
 354        }
 355        kempld_release_mutex(pld);
 356
 357        i2c_del_adapter(&i2c->adap);
 358
 359        return 0;
 360}
 361
 362#ifdef CONFIG_PM
 363static int kempld_i2c_suspend(struct platform_device *pdev, pm_message_t state)
 364{
 365        struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
 366        struct kempld_device_data *pld = i2c->pld;
 367        u8 ctrl;
 368
 369        kempld_get_mutex(pld);
 370        ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
 371        ctrl &= ~I2C_CTRL_EN;
 372        kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
 373        kempld_release_mutex(pld);
 374
 375        return 0;
 376}
 377
 378static int kempld_i2c_resume(struct platform_device *pdev)
 379{
 380        struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
 381        struct kempld_device_data *pld = i2c->pld;
 382
 383        kempld_get_mutex(pld);
 384        kempld_i2c_device_init(i2c);
 385        kempld_release_mutex(pld);
 386
 387        return 0;
 388}
 389#else
 390#define kempld_i2c_suspend      NULL
 391#define kempld_i2c_resume       NULL
 392#endif
 393
 394static struct platform_driver kempld_i2c_driver = {
 395        .driver = {
 396                .name = "kempld-i2c",
 397        },
 398        .probe          = kempld_i2c_probe,
 399        .remove         = kempld_i2c_remove,
 400        .suspend        = kempld_i2c_suspend,
 401        .resume         = kempld_i2c_resume,
 402};
 403
 404module_platform_driver(kempld_i2c_driver);
 405
 406MODULE_DESCRIPTION("KEM PLD I2C Driver");
 407MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
 408MODULE_LICENSE("GPL");
 409MODULE_ALIAS("platform:kempld_i2c");
 410