1f4e8afdcSSundar Iyer /* 2f4e8afdcSSundar Iyer * Copyright (C) ST-Ericsson SA 2010 3f4e8afdcSSundar Iyer * 4f4e8afdcSSundar Iyer * License Terms: GNU General Public License, version 2 5f4e8afdcSSundar Iyer * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson 6f4e8afdcSSundar Iyer * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson 7f4e8afdcSSundar Iyer */ 8f4e8afdcSSundar Iyer 9f4e8afdcSSundar Iyer #include <linux/module.h> 10f4e8afdcSSundar Iyer #include <linux/interrupt.h> 11f4e8afdcSSundar Iyer #include <linux/irq.h> 12f4e8afdcSSundar Iyer #include <linux/slab.h> 13f4e8afdcSSundar Iyer #include <linux/i2c.h> 14f4e8afdcSSundar Iyer #include <linux/mfd/core.h> 15f4e8afdcSSundar Iyer #include <linux/mfd/tc3589x.h> 16f4e8afdcSSundar Iyer 17f4e8afdcSSundar Iyer /** 1820406ebfSSundar Iyer * tc3589x_reg_read() - read a single TC3589x register 1920406ebfSSundar Iyer * @tc3589x: Device to read from 20f4e8afdcSSundar Iyer * @reg: Register to read 21f4e8afdcSSundar Iyer */ 2220406ebfSSundar Iyer int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg) 23f4e8afdcSSundar Iyer { 24f4e8afdcSSundar Iyer int ret; 25f4e8afdcSSundar Iyer 2620406ebfSSundar Iyer ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg); 27f4e8afdcSSundar Iyer if (ret < 0) 2820406ebfSSundar Iyer dev_err(tc3589x->dev, "failed to read reg %#x: %d\n", 29f4e8afdcSSundar Iyer reg, ret); 30f4e8afdcSSundar Iyer 31f4e8afdcSSundar Iyer return ret; 32f4e8afdcSSundar Iyer } 3320406ebfSSundar Iyer EXPORT_SYMBOL_GPL(tc3589x_reg_read); 34f4e8afdcSSundar Iyer 35f4e8afdcSSundar Iyer /** 3620406ebfSSundar Iyer * tc3589x_reg_read() - write a single TC3589x register 3720406ebfSSundar Iyer * @tc3589x: Device to write to 38f4e8afdcSSundar Iyer * @reg: Register to read 39f4e8afdcSSundar Iyer * @data: Value to write 40f4e8afdcSSundar Iyer */ 4120406ebfSSundar Iyer int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data) 42f4e8afdcSSundar Iyer { 43f4e8afdcSSundar Iyer int ret; 44f4e8afdcSSundar Iyer 4520406ebfSSundar Iyer ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data); 46f4e8afdcSSundar Iyer if (ret < 0) 4720406ebfSSundar Iyer dev_err(tc3589x->dev, "failed to write reg %#x: %d\n", 48f4e8afdcSSundar Iyer reg, ret); 49f4e8afdcSSundar Iyer 50f4e8afdcSSundar Iyer return ret; 51f4e8afdcSSundar Iyer } 5220406ebfSSundar Iyer EXPORT_SYMBOL_GPL(tc3589x_reg_write); 53f4e8afdcSSundar Iyer 54f4e8afdcSSundar Iyer /** 5520406ebfSSundar Iyer * tc3589x_block_read() - read multiple TC3589x registers 5620406ebfSSundar Iyer * @tc3589x: Device to read from 57f4e8afdcSSundar Iyer * @reg: First register 58f4e8afdcSSundar Iyer * @length: Number of registers 59f4e8afdcSSundar Iyer * @values: Buffer to write to 60f4e8afdcSSundar Iyer */ 6120406ebfSSundar Iyer int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values) 62f4e8afdcSSundar Iyer { 63f4e8afdcSSundar Iyer int ret; 64f4e8afdcSSundar Iyer 6520406ebfSSundar Iyer ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values); 66f4e8afdcSSundar Iyer if (ret < 0) 6720406ebfSSundar Iyer dev_err(tc3589x->dev, "failed to read regs %#x: %d\n", 68f4e8afdcSSundar Iyer reg, ret); 69f4e8afdcSSundar Iyer 70f4e8afdcSSundar Iyer return ret; 71f4e8afdcSSundar Iyer } 7220406ebfSSundar Iyer EXPORT_SYMBOL_GPL(tc3589x_block_read); 73f4e8afdcSSundar Iyer 74f4e8afdcSSundar Iyer /** 7520406ebfSSundar Iyer * tc3589x_block_write() - write multiple TC3589x registers 7620406ebfSSundar Iyer * @tc3589x: Device to write to 77f4e8afdcSSundar Iyer * @reg: First register 78f4e8afdcSSundar Iyer * @length: Number of registers 79f4e8afdcSSundar Iyer * @values: Values to write 80f4e8afdcSSundar Iyer */ 8120406ebfSSundar Iyer int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length, 82f4e8afdcSSundar Iyer const u8 *values) 83f4e8afdcSSundar Iyer { 84f4e8afdcSSundar Iyer int ret; 85f4e8afdcSSundar Iyer 8620406ebfSSundar Iyer ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length, 87f4e8afdcSSundar Iyer values); 88f4e8afdcSSundar Iyer if (ret < 0) 8920406ebfSSundar Iyer dev_err(tc3589x->dev, "failed to write regs %#x: %d\n", 90f4e8afdcSSundar Iyer reg, ret); 91f4e8afdcSSundar Iyer 92f4e8afdcSSundar Iyer return ret; 93f4e8afdcSSundar Iyer } 9420406ebfSSundar Iyer EXPORT_SYMBOL_GPL(tc3589x_block_write); 95f4e8afdcSSundar Iyer 96f4e8afdcSSundar Iyer /** 9720406ebfSSundar Iyer * tc3589x_set_bits() - set the value of a bitfield in a TC3589x register 9820406ebfSSundar Iyer * @tc3589x: Device to write to 99f4e8afdcSSundar Iyer * @reg: Register to write 100f4e8afdcSSundar Iyer * @mask: Mask of bits to set 101f4e8afdcSSundar Iyer * @values: Value to set 102f4e8afdcSSundar Iyer */ 10320406ebfSSundar Iyer int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val) 104f4e8afdcSSundar Iyer { 105f4e8afdcSSundar Iyer int ret; 106f4e8afdcSSundar Iyer 10720406ebfSSundar Iyer mutex_lock(&tc3589x->lock); 108f4e8afdcSSundar Iyer 10920406ebfSSundar Iyer ret = tc3589x_reg_read(tc3589x, reg); 110f4e8afdcSSundar Iyer if (ret < 0) 111f4e8afdcSSundar Iyer goto out; 112f4e8afdcSSundar Iyer 113f4e8afdcSSundar Iyer ret &= ~mask; 114f4e8afdcSSundar Iyer ret |= val; 115f4e8afdcSSundar Iyer 11620406ebfSSundar Iyer ret = tc3589x_reg_write(tc3589x, reg, ret); 117f4e8afdcSSundar Iyer 118f4e8afdcSSundar Iyer out: 11920406ebfSSundar Iyer mutex_unlock(&tc3589x->lock); 120f4e8afdcSSundar Iyer return ret; 121f4e8afdcSSundar Iyer } 12220406ebfSSundar Iyer EXPORT_SYMBOL_GPL(tc3589x_set_bits); 123f4e8afdcSSundar Iyer 124f4e8afdcSSundar Iyer static struct resource gpio_resources[] = { 125f4e8afdcSSundar Iyer { 12620406ebfSSundar Iyer .start = TC3589x_INT_GPIIRQ, 12720406ebfSSundar Iyer .end = TC3589x_INT_GPIIRQ, 128f4e8afdcSSundar Iyer .flags = IORESOURCE_IRQ, 129f4e8afdcSSundar Iyer }, 130f4e8afdcSSundar Iyer }; 131f4e8afdcSSundar Iyer 132*611b7590SSundar Iyer static struct mfd_cell tc3589x_dev_gpio[] = { 133f4e8afdcSSundar Iyer { 13420406ebfSSundar Iyer .name = "tc3589x-gpio", 135f4e8afdcSSundar Iyer .num_resources = ARRAY_SIZE(gpio_resources), 136f4e8afdcSSundar Iyer .resources = &gpio_resources[0], 137f4e8afdcSSundar Iyer }, 138f4e8afdcSSundar Iyer }; 139f4e8afdcSSundar Iyer 14020406ebfSSundar Iyer static irqreturn_t tc3589x_irq(int irq, void *data) 141f4e8afdcSSundar Iyer { 14220406ebfSSundar Iyer struct tc3589x *tc3589x = data; 143f4e8afdcSSundar Iyer int status; 144f4e8afdcSSundar Iyer 14520406ebfSSundar Iyer status = tc3589x_reg_read(tc3589x, TC3589x_IRQST); 146f4e8afdcSSundar Iyer if (status < 0) 147f4e8afdcSSundar Iyer return IRQ_NONE; 148f4e8afdcSSundar Iyer 149f4e8afdcSSundar Iyer while (status) { 150f4e8afdcSSundar Iyer int bit = __ffs(status); 151f4e8afdcSSundar Iyer 15220406ebfSSundar Iyer handle_nested_irq(tc3589x->irq_base + bit); 153f4e8afdcSSundar Iyer status &= ~(1 << bit); 154f4e8afdcSSundar Iyer } 155f4e8afdcSSundar Iyer 156f4e8afdcSSundar Iyer /* 157f4e8afdcSSundar Iyer * A dummy read or write (to any register) appears to be necessary to 158f4e8afdcSSundar Iyer * have the last interrupt clear (for example, GPIO IC write) take 159f4e8afdcSSundar Iyer * effect. 160f4e8afdcSSundar Iyer */ 16120406ebfSSundar Iyer tc3589x_reg_read(tc3589x, TC3589x_IRQST); 162f4e8afdcSSundar Iyer 163f4e8afdcSSundar Iyer return IRQ_HANDLED; 164f4e8afdcSSundar Iyer } 165f4e8afdcSSundar Iyer 16620406ebfSSundar Iyer static void tc3589x_irq_dummy(unsigned int irq) 167f4e8afdcSSundar Iyer { 168f4e8afdcSSundar Iyer /* No mask/unmask at this level */ 169f4e8afdcSSundar Iyer } 170f4e8afdcSSundar Iyer 17120406ebfSSundar Iyer static struct irq_chip tc3589x_irq_chip = { 17220406ebfSSundar Iyer .name = "tc3589x", 17320406ebfSSundar Iyer .mask = tc3589x_irq_dummy, 17420406ebfSSundar Iyer .unmask = tc3589x_irq_dummy, 175f4e8afdcSSundar Iyer }; 176f4e8afdcSSundar Iyer 17720406ebfSSundar Iyer static int tc3589x_irq_init(struct tc3589x *tc3589x) 178f4e8afdcSSundar Iyer { 17920406ebfSSundar Iyer int base = tc3589x->irq_base; 180f4e8afdcSSundar Iyer int irq; 181f4e8afdcSSundar Iyer 18220406ebfSSundar Iyer for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { 18320406ebfSSundar Iyer set_irq_chip_data(irq, tc3589x); 18420406ebfSSundar Iyer set_irq_chip_and_handler(irq, &tc3589x_irq_chip, 185f4e8afdcSSundar Iyer handle_edge_irq); 186f4e8afdcSSundar Iyer set_irq_nested_thread(irq, 1); 187f4e8afdcSSundar Iyer #ifdef CONFIG_ARM 188f4e8afdcSSundar Iyer set_irq_flags(irq, IRQF_VALID); 189f4e8afdcSSundar Iyer #else 190f4e8afdcSSundar Iyer set_irq_noprobe(irq); 191f4e8afdcSSundar Iyer #endif 192f4e8afdcSSundar Iyer } 193f4e8afdcSSundar Iyer 194f4e8afdcSSundar Iyer return 0; 195f4e8afdcSSundar Iyer } 196f4e8afdcSSundar Iyer 19720406ebfSSundar Iyer static void tc3589x_irq_remove(struct tc3589x *tc3589x) 198f4e8afdcSSundar Iyer { 19920406ebfSSundar Iyer int base = tc3589x->irq_base; 200f4e8afdcSSundar Iyer int irq; 201f4e8afdcSSundar Iyer 20220406ebfSSundar Iyer for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { 203f4e8afdcSSundar Iyer #ifdef CONFIG_ARM 204f4e8afdcSSundar Iyer set_irq_flags(irq, 0); 205f4e8afdcSSundar Iyer #endif 206f4e8afdcSSundar Iyer set_irq_chip_and_handler(irq, NULL, NULL); 207f4e8afdcSSundar Iyer set_irq_chip_data(irq, NULL); 208f4e8afdcSSundar Iyer } 209f4e8afdcSSundar Iyer } 210f4e8afdcSSundar Iyer 21120406ebfSSundar Iyer static int tc3589x_chip_init(struct tc3589x *tc3589x) 212f4e8afdcSSundar Iyer { 213f4e8afdcSSundar Iyer int manf, ver, ret; 214f4e8afdcSSundar Iyer 21520406ebfSSundar Iyer manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE); 216f4e8afdcSSundar Iyer if (manf < 0) 217f4e8afdcSSundar Iyer return manf; 218f4e8afdcSSundar Iyer 21920406ebfSSundar Iyer ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION); 220f4e8afdcSSundar Iyer if (ver < 0) 221f4e8afdcSSundar Iyer return ver; 222f4e8afdcSSundar Iyer 22320406ebfSSundar Iyer if (manf != TC3589x_MANFCODE_MAGIC) { 22420406ebfSSundar Iyer dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf); 225f4e8afdcSSundar Iyer return -EINVAL; 226f4e8afdcSSundar Iyer } 227f4e8afdcSSundar Iyer 22820406ebfSSundar Iyer dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x\n", manf, ver); 229f4e8afdcSSundar Iyer 230f4e8afdcSSundar Iyer /* Put everything except the IRQ module into reset */ 23120406ebfSSundar Iyer ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL, 23220406ebfSSundar Iyer TC3589x_RSTCTRL_TIMRST 23320406ebfSSundar Iyer | TC3589x_RSTCTRL_ROTRST 23420406ebfSSundar Iyer | TC3589x_RSTCTRL_KBDRST 23520406ebfSSundar Iyer | TC3589x_RSTCTRL_GPIRST); 236f4e8afdcSSundar Iyer if (ret < 0) 237f4e8afdcSSundar Iyer return ret; 238f4e8afdcSSundar Iyer 239f4e8afdcSSundar Iyer /* Clear the reset interrupt. */ 24020406ebfSSundar Iyer return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1); 241f4e8afdcSSundar Iyer } 242f4e8afdcSSundar Iyer 243*611b7590SSundar Iyer static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) 244*611b7590SSundar Iyer { 245*611b7590SSundar Iyer int ret = 0; 246*611b7590SSundar Iyer unsigned int blocks = tc3589x->pdata->block; 247*611b7590SSundar Iyer 248*611b7590SSundar Iyer if (blocks & TC3589x_BLOCK_GPIO) { 249*611b7590SSundar Iyer ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, 250*611b7590SSundar Iyer ARRAY_SIZE(tc3589x_dev_gpio), NULL, 251*611b7590SSundar Iyer tc3589x->irq_base); 252*611b7590SSundar Iyer if (ret) { 253*611b7590SSundar Iyer dev_err(tc3589x->dev, "failed to add gpio child\n"); 254*611b7590SSundar Iyer return ret; 255*611b7590SSundar Iyer } 256*611b7590SSundar Iyer dev_info(tc3589x->dev, "added gpio block\n"); 257*611b7590SSundar Iyer } 258*611b7590SSundar Iyer 259*611b7590SSundar Iyer return ret; 260*611b7590SSundar Iyer 261*611b7590SSundar Iyer } 262*611b7590SSundar Iyer 26320406ebfSSundar Iyer static int __devinit tc3589x_probe(struct i2c_client *i2c, 264f4e8afdcSSundar Iyer const struct i2c_device_id *id) 265f4e8afdcSSundar Iyer { 26620406ebfSSundar Iyer struct tc3589x_platform_data *pdata = i2c->dev.platform_data; 26720406ebfSSundar Iyer struct tc3589x *tc3589x; 268f4e8afdcSSundar Iyer int ret; 269f4e8afdcSSundar Iyer 270f4e8afdcSSundar Iyer if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA 271f4e8afdcSSundar Iyer | I2C_FUNC_SMBUS_I2C_BLOCK)) 272f4e8afdcSSundar Iyer return -EIO; 273f4e8afdcSSundar Iyer 27420406ebfSSundar Iyer tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL); 27520406ebfSSundar Iyer if (!tc3589x) 276f4e8afdcSSundar Iyer return -ENOMEM; 277f4e8afdcSSundar Iyer 27820406ebfSSundar Iyer mutex_init(&tc3589x->lock); 279f4e8afdcSSundar Iyer 28020406ebfSSundar Iyer tc3589x->dev = &i2c->dev; 28120406ebfSSundar Iyer tc3589x->i2c = i2c; 28220406ebfSSundar Iyer tc3589x->pdata = pdata; 28320406ebfSSundar Iyer tc3589x->irq_base = pdata->irq_base; 28420406ebfSSundar Iyer tc3589x->num_gpio = id->driver_data; 285f4e8afdcSSundar Iyer 28620406ebfSSundar Iyer i2c_set_clientdata(i2c, tc3589x); 287f4e8afdcSSundar Iyer 28820406ebfSSundar Iyer ret = tc3589x_chip_init(tc3589x); 289f4e8afdcSSundar Iyer if (ret) 290f4e8afdcSSundar Iyer goto out_free; 291f4e8afdcSSundar Iyer 29220406ebfSSundar Iyer ret = tc3589x_irq_init(tc3589x); 293f4e8afdcSSundar Iyer if (ret) 294f4e8afdcSSundar Iyer goto out_free; 295f4e8afdcSSundar Iyer 29620406ebfSSundar Iyer ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq, 297f4e8afdcSSundar Iyer IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 29820406ebfSSundar Iyer "tc3589x", tc3589x); 299f4e8afdcSSundar Iyer if (ret) { 30020406ebfSSundar Iyer dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); 301f4e8afdcSSundar Iyer goto out_removeirq; 302f4e8afdcSSundar Iyer } 303f4e8afdcSSundar Iyer 304*611b7590SSundar Iyer ret = tc3589x_device_init(tc3589x); 305f4e8afdcSSundar Iyer if (ret) { 306*611b7590SSundar Iyer dev_err(tc3589x->dev, "failed to add child devices\n"); 307f4e8afdcSSundar Iyer goto out_freeirq; 308f4e8afdcSSundar Iyer } 309f4e8afdcSSundar Iyer 310f4e8afdcSSundar Iyer return 0; 311f4e8afdcSSundar Iyer 312f4e8afdcSSundar Iyer out_freeirq: 31320406ebfSSundar Iyer free_irq(tc3589x->i2c->irq, tc3589x); 314f4e8afdcSSundar Iyer out_removeirq: 31520406ebfSSundar Iyer tc3589x_irq_remove(tc3589x); 316f4e8afdcSSundar Iyer out_free: 31720406ebfSSundar Iyer kfree(tc3589x); 318f4e8afdcSSundar Iyer return ret; 319f4e8afdcSSundar Iyer } 320f4e8afdcSSundar Iyer 32120406ebfSSundar Iyer static int __devexit tc3589x_remove(struct i2c_client *client) 322f4e8afdcSSundar Iyer { 32320406ebfSSundar Iyer struct tc3589x *tc3589x = i2c_get_clientdata(client); 324f4e8afdcSSundar Iyer 32520406ebfSSundar Iyer mfd_remove_devices(tc3589x->dev); 326f4e8afdcSSundar Iyer 32720406ebfSSundar Iyer free_irq(tc3589x->i2c->irq, tc3589x); 32820406ebfSSundar Iyer tc3589x_irq_remove(tc3589x); 329f4e8afdcSSundar Iyer 33020406ebfSSundar Iyer kfree(tc3589x); 331f4e8afdcSSundar Iyer 332f4e8afdcSSundar Iyer return 0; 333f4e8afdcSSundar Iyer } 334f4e8afdcSSundar Iyer 33520406ebfSSundar Iyer static const struct i2c_device_id tc3589x_id[] = { 33620406ebfSSundar Iyer { "tc3589x", 24 }, 337f4e8afdcSSundar Iyer { } 338f4e8afdcSSundar Iyer }; 33920406ebfSSundar Iyer MODULE_DEVICE_TABLE(i2c, tc3589x_id); 340f4e8afdcSSundar Iyer 34120406ebfSSundar Iyer static struct i2c_driver tc3589x_driver = { 34220406ebfSSundar Iyer .driver.name = "tc3589x", 343f4e8afdcSSundar Iyer .driver.owner = THIS_MODULE, 34420406ebfSSundar Iyer .probe = tc3589x_probe, 34520406ebfSSundar Iyer .remove = __devexit_p(tc3589x_remove), 34620406ebfSSundar Iyer .id_table = tc3589x_id, 347f4e8afdcSSundar Iyer }; 348f4e8afdcSSundar Iyer 34920406ebfSSundar Iyer static int __init tc3589x_init(void) 350f4e8afdcSSundar Iyer { 35120406ebfSSundar Iyer return i2c_add_driver(&tc3589x_driver); 352f4e8afdcSSundar Iyer } 35320406ebfSSundar Iyer subsys_initcall(tc3589x_init); 354f4e8afdcSSundar Iyer 35520406ebfSSundar Iyer static void __exit tc3589x_exit(void) 356f4e8afdcSSundar Iyer { 35720406ebfSSundar Iyer i2c_del_driver(&tc3589x_driver); 358f4e8afdcSSundar Iyer } 35920406ebfSSundar Iyer module_exit(tc3589x_exit); 360f4e8afdcSSundar Iyer 361f4e8afdcSSundar Iyer MODULE_LICENSE("GPL v2"); 36220406ebfSSundar Iyer MODULE_DESCRIPTION("TC3589x MFD core driver"); 363f4e8afdcSSundar Iyer MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); 364