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