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> 1215e27b10SLee Jones #include <linux/irqdomain.h> 13f4e8afdcSSundar Iyer #include <linux/slab.h> 14f4e8afdcSSundar Iyer #include <linux/i2c.h> 15a435ae1dSLee Jones #include <linux/of.h> 16f4e8afdcSSundar Iyer #include <linux/mfd/core.h> 17f4e8afdcSSundar Iyer #include <linux/mfd/tc3589x.h> 18f4e8afdcSSundar Iyer 19*e64c1eb4SLinus Walleij /** 20*e64c1eb4SLinus Walleij * enum tc3589x_version - indicates the TC3589x version 21*e64c1eb4SLinus Walleij */ 22*e64c1eb4SLinus Walleij enum tc3589x_version { 23*e64c1eb4SLinus Walleij TC3589X_TC35890, 24*e64c1eb4SLinus Walleij TC3589X_TC35892, 25*e64c1eb4SLinus Walleij TC3589X_TC35893, 26*e64c1eb4SLinus Walleij TC3589X_TC35894, 27*e64c1eb4SLinus Walleij TC3589X_TC35895, 28*e64c1eb4SLinus Walleij TC3589X_TC35896, 29*e64c1eb4SLinus Walleij TC3589X_UNKNOWN, 30*e64c1eb4SLinus Walleij }; 31*e64c1eb4SLinus Walleij 32593e9d70SSundar Iyer #define TC3589x_CLKMODE_MODCTL_SLEEP 0x0 33593e9d70SSundar Iyer #define TC3589x_CLKMODE_MODCTL_OPERATION (1 << 0) 34593e9d70SSundar Iyer 35f4e8afdcSSundar Iyer /** 3620406ebfSSundar Iyer * tc3589x_reg_read() - read a single TC3589x register 3720406ebfSSundar Iyer * @tc3589x: Device to read from 38f4e8afdcSSundar Iyer * @reg: Register to read 39f4e8afdcSSundar Iyer */ 4020406ebfSSundar Iyer int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg) 41f4e8afdcSSundar Iyer { 42f4e8afdcSSundar Iyer int ret; 43f4e8afdcSSundar Iyer 4420406ebfSSundar Iyer ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg); 45f4e8afdcSSundar Iyer if (ret < 0) 4620406ebfSSundar Iyer dev_err(tc3589x->dev, "failed to read reg %#x: %d\n", 47f4e8afdcSSundar Iyer reg, ret); 48f4e8afdcSSundar Iyer 49f4e8afdcSSundar Iyer return ret; 50f4e8afdcSSundar Iyer } 5120406ebfSSundar Iyer EXPORT_SYMBOL_GPL(tc3589x_reg_read); 52f4e8afdcSSundar Iyer 53f4e8afdcSSundar Iyer /** 5420406ebfSSundar Iyer * tc3589x_reg_read() - write a single TC3589x register 5520406ebfSSundar Iyer * @tc3589x: Device to write to 56f4e8afdcSSundar Iyer * @reg: Register to read 57f4e8afdcSSundar Iyer * @data: Value to write 58f4e8afdcSSundar Iyer */ 5920406ebfSSundar Iyer int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data) 60f4e8afdcSSundar Iyer { 61f4e8afdcSSundar Iyer int ret; 62f4e8afdcSSundar Iyer 6320406ebfSSundar Iyer ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data); 64f4e8afdcSSundar Iyer if (ret < 0) 6520406ebfSSundar Iyer dev_err(tc3589x->dev, "failed to write reg %#x: %d\n", 66f4e8afdcSSundar Iyer reg, ret); 67f4e8afdcSSundar Iyer 68f4e8afdcSSundar Iyer return ret; 69f4e8afdcSSundar Iyer } 7020406ebfSSundar Iyer EXPORT_SYMBOL_GPL(tc3589x_reg_write); 71f4e8afdcSSundar Iyer 72f4e8afdcSSundar Iyer /** 7320406ebfSSundar Iyer * tc3589x_block_read() - read multiple TC3589x registers 7420406ebfSSundar Iyer * @tc3589x: Device to read from 75f4e8afdcSSundar Iyer * @reg: First register 76f4e8afdcSSundar Iyer * @length: Number of registers 77f4e8afdcSSundar Iyer * @values: Buffer to write to 78f4e8afdcSSundar Iyer */ 7920406ebfSSundar Iyer int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values) 80f4e8afdcSSundar Iyer { 81f4e8afdcSSundar Iyer int ret; 82f4e8afdcSSundar Iyer 8320406ebfSSundar Iyer ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values); 84f4e8afdcSSundar Iyer if (ret < 0) 8520406ebfSSundar Iyer dev_err(tc3589x->dev, "failed to read regs %#x: %d\n", 86f4e8afdcSSundar Iyer reg, ret); 87f4e8afdcSSundar Iyer 88f4e8afdcSSundar Iyer return ret; 89f4e8afdcSSundar Iyer } 9020406ebfSSundar Iyer EXPORT_SYMBOL_GPL(tc3589x_block_read); 91f4e8afdcSSundar Iyer 92f4e8afdcSSundar Iyer /** 9320406ebfSSundar Iyer * tc3589x_block_write() - write multiple TC3589x registers 9420406ebfSSundar Iyer * @tc3589x: Device to write to 95f4e8afdcSSundar Iyer * @reg: First register 96f4e8afdcSSundar Iyer * @length: Number of registers 97f4e8afdcSSundar Iyer * @values: Values to write 98f4e8afdcSSundar Iyer */ 9920406ebfSSundar Iyer int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length, 100f4e8afdcSSundar Iyer const u8 *values) 101f4e8afdcSSundar Iyer { 102f4e8afdcSSundar Iyer int ret; 103f4e8afdcSSundar Iyer 10420406ebfSSundar Iyer ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length, 105f4e8afdcSSundar Iyer values); 106f4e8afdcSSundar Iyer if (ret < 0) 10720406ebfSSundar Iyer dev_err(tc3589x->dev, "failed to write regs %#x: %d\n", 108f4e8afdcSSundar Iyer reg, ret); 109f4e8afdcSSundar Iyer 110f4e8afdcSSundar Iyer return ret; 111f4e8afdcSSundar Iyer } 11220406ebfSSundar Iyer EXPORT_SYMBOL_GPL(tc3589x_block_write); 113f4e8afdcSSundar Iyer 114f4e8afdcSSundar Iyer /** 11520406ebfSSundar Iyer * tc3589x_set_bits() - set the value of a bitfield in a TC3589x register 11620406ebfSSundar Iyer * @tc3589x: Device to write to 117f4e8afdcSSundar Iyer * @reg: Register to write 118f4e8afdcSSundar Iyer * @mask: Mask of bits to set 119f4e8afdcSSundar Iyer * @values: Value to set 120f4e8afdcSSundar Iyer */ 12120406ebfSSundar Iyer int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val) 122f4e8afdcSSundar Iyer { 123f4e8afdcSSundar Iyer int ret; 124f4e8afdcSSundar Iyer 12520406ebfSSundar Iyer mutex_lock(&tc3589x->lock); 126f4e8afdcSSundar Iyer 12720406ebfSSundar Iyer ret = tc3589x_reg_read(tc3589x, reg); 128f4e8afdcSSundar Iyer if (ret < 0) 129f4e8afdcSSundar Iyer goto out; 130f4e8afdcSSundar Iyer 131f4e8afdcSSundar Iyer ret &= ~mask; 132f4e8afdcSSundar Iyer ret |= val; 133f4e8afdcSSundar Iyer 13420406ebfSSundar Iyer ret = tc3589x_reg_write(tc3589x, reg, ret); 135f4e8afdcSSundar Iyer 136f4e8afdcSSundar Iyer out: 13720406ebfSSundar Iyer mutex_unlock(&tc3589x->lock); 138f4e8afdcSSundar Iyer return ret; 139f4e8afdcSSundar Iyer } 14020406ebfSSundar Iyer EXPORT_SYMBOL_GPL(tc3589x_set_bits); 141f4e8afdcSSundar Iyer 142f4e8afdcSSundar Iyer static struct resource gpio_resources[] = { 143f4e8afdcSSundar Iyer { 14420406ebfSSundar Iyer .start = TC3589x_INT_GPIIRQ, 14520406ebfSSundar Iyer .end = TC3589x_INT_GPIIRQ, 146f4e8afdcSSundar Iyer .flags = IORESOURCE_IRQ, 147f4e8afdcSSundar Iyer }, 148f4e8afdcSSundar Iyer }; 149f4e8afdcSSundar Iyer 15009c730a4SSundar Iyer static struct resource keypad_resources[] = { 15109c730a4SSundar Iyer { 15209c730a4SSundar Iyer .start = TC3589x_INT_KBDIRQ, 15309c730a4SSundar Iyer .end = TC3589x_INT_KBDIRQ, 15409c730a4SSundar Iyer .flags = IORESOURCE_IRQ, 15509c730a4SSundar Iyer }, 15609c730a4SSundar Iyer }; 15709c730a4SSundar Iyer 158611b7590SSundar Iyer static struct mfd_cell tc3589x_dev_gpio[] = { 159f4e8afdcSSundar Iyer { 16020406ebfSSundar Iyer .name = "tc3589x-gpio", 161f4e8afdcSSundar Iyer .num_resources = ARRAY_SIZE(gpio_resources), 162f4e8afdcSSundar Iyer .resources = &gpio_resources[0], 163a435ae1dSLee Jones .of_compatible = "tc3589x-gpio", 164f4e8afdcSSundar Iyer }, 165f4e8afdcSSundar Iyer }; 166f4e8afdcSSundar Iyer 16709c730a4SSundar Iyer static struct mfd_cell tc3589x_dev_keypad[] = { 16809c730a4SSundar Iyer { 16909c730a4SSundar Iyer .name = "tc3589x-keypad", 17009c730a4SSundar Iyer .num_resources = ARRAY_SIZE(keypad_resources), 17109c730a4SSundar Iyer .resources = &keypad_resources[0], 172a435ae1dSLee Jones .of_compatible = "tc3589x-keypad", 17309c730a4SSundar Iyer }, 17409c730a4SSundar Iyer }; 17509c730a4SSundar Iyer 17620406ebfSSundar Iyer static irqreturn_t tc3589x_irq(int irq, void *data) 177f4e8afdcSSundar Iyer { 17820406ebfSSundar Iyer struct tc3589x *tc3589x = data; 179f4e8afdcSSundar Iyer int status; 180f4e8afdcSSundar Iyer 181bd77efd0SSundar Iyer again: 18220406ebfSSundar Iyer status = tc3589x_reg_read(tc3589x, TC3589x_IRQST); 183f4e8afdcSSundar Iyer if (status < 0) 184f4e8afdcSSundar Iyer return IRQ_NONE; 185f4e8afdcSSundar Iyer 186f4e8afdcSSundar Iyer while (status) { 187f4e8afdcSSundar Iyer int bit = __ffs(status); 18815e27b10SLee Jones int virq = irq_create_mapping(tc3589x->domain, bit); 189f4e8afdcSSundar Iyer 19015e27b10SLee Jones handle_nested_irq(virq); 191f4e8afdcSSundar Iyer status &= ~(1 << bit); 192f4e8afdcSSundar Iyer } 193f4e8afdcSSundar Iyer 194f4e8afdcSSundar Iyer /* 195f4e8afdcSSundar Iyer * A dummy read or write (to any register) appears to be necessary to 196f4e8afdcSSundar Iyer * have the last interrupt clear (for example, GPIO IC write) take 197bd77efd0SSundar Iyer * effect. In such a case, recheck for any interrupt which is still 198bd77efd0SSundar Iyer * pending. 199f4e8afdcSSundar Iyer */ 200bd77efd0SSundar Iyer status = tc3589x_reg_read(tc3589x, TC3589x_IRQST); 201bd77efd0SSundar Iyer if (status) 202bd77efd0SSundar Iyer goto again; 203f4e8afdcSSundar Iyer 204f4e8afdcSSundar Iyer return IRQ_HANDLED; 205f4e8afdcSSundar Iyer } 206f4e8afdcSSundar Iyer 20715e27b10SLee Jones static int tc3589x_irq_map(struct irq_domain *d, unsigned int virq, 20815e27b10SLee Jones irq_hw_number_t hwirq) 209f4e8afdcSSundar Iyer { 21015e27b10SLee Jones struct tc3589x *tc3589x = d->host_data; 211f4e8afdcSSundar Iyer 21215e27b10SLee Jones irq_set_chip_data(virq, tc3589x); 21315e27b10SLee Jones irq_set_chip_and_handler(virq, &dummy_irq_chip, 214f4e8afdcSSundar Iyer handle_edge_irq); 21515e27b10SLee Jones irq_set_nested_thread(virq, 1); 216f4e8afdcSSundar Iyer #ifdef CONFIG_ARM 21715e27b10SLee Jones set_irq_flags(virq, IRQF_VALID); 218f4e8afdcSSundar Iyer #else 21915e27b10SLee Jones irq_set_noprobe(virq); 220f4e8afdcSSundar Iyer #endif 221f4e8afdcSSundar Iyer 222f4e8afdcSSundar Iyer return 0; 223f4e8afdcSSundar Iyer } 224f4e8afdcSSundar Iyer 22515e27b10SLee Jones static void tc3589x_irq_unmap(struct irq_domain *d, unsigned int virq) 22615e27b10SLee Jones { 22715e27b10SLee Jones #ifdef CONFIG_ARM 22815e27b10SLee Jones set_irq_flags(virq, 0); 22915e27b10SLee Jones #endif 23015e27b10SLee Jones irq_set_chip_and_handler(virq, NULL, NULL); 23115e27b10SLee Jones irq_set_chip_data(virq, NULL); 23215e27b10SLee Jones } 23315e27b10SLee Jones 23415e27b10SLee Jones static struct irq_domain_ops tc3589x_irq_ops = { 23515e27b10SLee Jones .map = tc3589x_irq_map, 23615e27b10SLee Jones .unmap = tc3589x_irq_unmap, 23715e27b10SLee Jones .xlate = irq_domain_xlate_twocell, 23815e27b10SLee Jones }; 23915e27b10SLee Jones 240a435ae1dSLee Jones static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np) 241f4e8afdcSSundar Iyer { 24220406ebfSSundar Iyer int base = tc3589x->irq_base; 243f4e8afdcSSundar Iyer 2441f0529b4SLinus Walleij tc3589x->domain = irq_domain_add_simple( 2451f0529b4SLinus Walleij np, TC3589x_NR_INTERNAL_IRQS, base, 24615e27b10SLee Jones &tc3589x_irq_ops, tc3589x); 24715e27b10SLee Jones 24815e27b10SLee Jones if (!tc3589x->domain) { 24915e27b10SLee Jones dev_err(tc3589x->dev, "Failed to create irqdomain\n"); 25015e27b10SLee Jones return -ENOSYS; 25115e27b10SLee Jones } 25215e27b10SLee Jones 25315e27b10SLee Jones return 0; 254f4e8afdcSSundar Iyer } 255f4e8afdcSSundar Iyer 25620406ebfSSundar Iyer static int tc3589x_chip_init(struct tc3589x *tc3589x) 257f4e8afdcSSundar Iyer { 258f4e8afdcSSundar Iyer int manf, ver, ret; 259f4e8afdcSSundar Iyer 26020406ebfSSundar Iyer manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE); 261f4e8afdcSSundar Iyer if (manf < 0) 262f4e8afdcSSundar Iyer return manf; 263f4e8afdcSSundar Iyer 26420406ebfSSundar Iyer ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION); 265f4e8afdcSSundar Iyer if (ver < 0) 266f4e8afdcSSundar Iyer return ver; 267f4e8afdcSSundar Iyer 26820406ebfSSundar Iyer if (manf != TC3589x_MANFCODE_MAGIC) { 26920406ebfSSundar Iyer dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf); 270f4e8afdcSSundar Iyer return -EINVAL; 271f4e8afdcSSundar Iyer } 272f4e8afdcSSundar Iyer 27320406ebfSSundar Iyer dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x\n", manf, ver); 274f4e8afdcSSundar Iyer 275523bc382SSundar Iyer /* 276523bc382SSundar Iyer * Put everything except the IRQ module into reset; 277523bc382SSundar Iyer * also spare the GPIO module for any pin initialization 278523bc382SSundar Iyer * done during pre-kernel boot 279523bc382SSundar Iyer */ 28020406ebfSSundar Iyer ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL, 28120406ebfSSundar Iyer TC3589x_RSTCTRL_TIMRST 28220406ebfSSundar Iyer | TC3589x_RSTCTRL_ROTRST 283523bc382SSundar Iyer | TC3589x_RSTCTRL_KBDRST); 284f4e8afdcSSundar Iyer if (ret < 0) 285f4e8afdcSSundar Iyer return ret; 286f4e8afdcSSundar Iyer 287f4e8afdcSSundar Iyer /* Clear the reset interrupt. */ 28820406ebfSSundar Iyer return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1); 289f4e8afdcSSundar Iyer } 290f4e8afdcSSundar Iyer 291f791be49SBill Pemberton static int tc3589x_device_init(struct tc3589x *tc3589x) 292611b7590SSundar Iyer { 293611b7590SSundar Iyer int ret = 0; 294611b7590SSundar Iyer unsigned int blocks = tc3589x->pdata->block; 295611b7590SSundar Iyer 296611b7590SSundar Iyer if (blocks & TC3589x_BLOCK_GPIO) { 297611b7590SSundar Iyer ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, 298611b7590SSundar Iyer ARRAY_SIZE(tc3589x_dev_gpio), NULL, 29915e27b10SLee Jones tc3589x->irq_base, tc3589x->domain); 300611b7590SSundar Iyer if (ret) { 301611b7590SSundar Iyer dev_err(tc3589x->dev, "failed to add gpio child\n"); 302611b7590SSundar Iyer return ret; 303611b7590SSundar Iyer } 304611b7590SSundar Iyer dev_info(tc3589x->dev, "added gpio block\n"); 305611b7590SSundar Iyer } 306611b7590SSundar Iyer 30709c730a4SSundar Iyer if (blocks & TC3589x_BLOCK_KEYPAD) { 30809c730a4SSundar Iyer ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, 30909c730a4SSundar Iyer ARRAY_SIZE(tc3589x_dev_keypad), NULL, 31015e27b10SLee Jones tc3589x->irq_base, tc3589x->domain); 31109c730a4SSundar Iyer if (ret) { 31209c730a4SSundar Iyer dev_err(tc3589x->dev, "failed to keypad child\n"); 313611b7590SSundar Iyer return ret; 31409c730a4SSundar Iyer } 31509c730a4SSundar Iyer dev_info(tc3589x->dev, "added keypad block\n"); 31609c730a4SSundar Iyer } 317611b7590SSundar Iyer 31809c730a4SSundar Iyer return ret; 319611b7590SSundar Iyer } 320611b7590SSundar Iyer 321a435ae1dSLee Jones static int tc3589x_of_probe(struct device_node *np, 322a435ae1dSLee Jones struct tc3589x_platform_data *pdata) 323a435ae1dSLee Jones { 324a435ae1dSLee Jones struct device_node *child; 325a435ae1dSLee Jones 326a435ae1dSLee Jones for_each_child_of_node(np, child) { 327a435ae1dSLee Jones if (!strcmp(child->name, "tc3589x_gpio")) { 328a435ae1dSLee Jones pdata->block |= TC3589x_BLOCK_GPIO; 329a435ae1dSLee Jones } 330a435ae1dSLee Jones if (!strcmp(child->name, "tc3589x_keypad")) { 331a435ae1dSLee Jones pdata->block |= TC3589x_BLOCK_KEYPAD; 332a435ae1dSLee Jones } 333a435ae1dSLee Jones } 334a435ae1dSLee Jones 335a435ae1dSLee Jones return 0; 336a435ae1dSLee Jones } 337a435ae1dSLee Jones 338f791be49SBill Pemberton static int tc3589x_probe(struct i2c_client *i2c, 339f4e8afdcSSundar Iyer const struct i2c_device_id *id) 340f4e8afdcSSundar Iyer { 341334a41ceSJingoo Han struct tc3589x_platform_data *pdata = dev_get_platdata(&i2c->dev); 342a435ae1dSLee Jones struct device_node *np = i2c->dev.of_node; 34320406ebfSSundar Iyer struct tc3589x *tc3589x; 344f4e8afdcSSundar Iyer int ret; 345f4e8afdcSSundar Iyer 346a435ae1dSLee Jones if (!pdata) { 347a435ae1dSLee Jones if (np) { 348a435ae1dSLee Jones pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); 349a435ae1dSLee Jones if (!pdata) 350a435ae1dSLee Jones return -ENOMEM; 351a435ae1dSLee Jones 352a435ae1dSLee Jones ret = tc3589x_of_probe(np, pdata); 353a435ae1dSLee Jones if (ret) 354a435ae1dSLee Jones return ret; 355a435ae1dSLee Jones } 356a435ae1dSLee Jones else { 357a435ae1dSLee Jones dev_err(&i2c->dev, "No platform data or DT found\n"); 358a435ae1dSLee Jones return -EINVAL; 359a435ae1dSLee Jones } 360a435ae1dSLee Jones } 361a435ae1dSLee Jones 362f4e8afdcSSundar Iyer if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA 363f4e8afdcSSundar Iyer | I2C_FUNC_SMBUS_I2C_BLOCK)) 364f4e8afdcSSundar Iyer return -EIO; 365f4e8afdcSSundar Iyer 3661383e00fSJingoo Han tc3589x = devm_kzalloc(&i2c->dev, sizeof(struct tc3589x), 3671383e00fSJingoo Han GFP_KERNEL); 36820406ebfSSundar Iyer if (!tc3589x) 369f4e8afdcSSundar Iyer return -ENOMEM; 370f4e8afdcSSundar Iyer 37120406ebfSSundar Iyer mutex_init(&tc3589x->lock); 372f4e8afdcSSundar Iyer 37320406ebfSSundar Iyer tc3589x->dev = &i2c->dev; 37420406ebfSSundar Iyer tc3589x->i2c = i2c; 37520406ebfSSundar Iyer tc3589x->pdata = pdata; 37620406ebfSSundar Iyer tc3589x->irq_base = pdata->irq_base; 377*e64c1eb4SLinus Walleij 378*e64c1eb4SLinus Walleij switch (id->driver_data) { 379*e64c1eb4SLinus Walleij case TC3589X_TC35893: 380*e64c1eb4SLinus Walleij case TC3589X_TC35895: 381*e64c1eb4SLinus Walleij case TC3589X_TC35896: 382*e64c1eb4SLinus Walleij tc3589x->num_gpio = 20; 383*e64c1eb4SLinus Walleij break; 384*e64c1eb4SLinus Walleij case TC3589X_TC35890: 385*e64c1eb4SLinus Walleij case TC3589X_TC35892: 386*e64c1eb4SLinus Walleij case TC3589X_TC35894: 387*e64c1eb4SLinus Walleij case TC3589X_UNKNOWN: 388*e64c1eb4SLinus Walleij default: 389*e64c1eb4SLinus Walleij tc3589x->num_gpio = 24; 390*e64c1eb4SLinus Walleij break; 391*e64c1eb4SLinus Walleij } 392f4e8afdcSSundar Iyer 39320406ebfSSundar Iyer i2c_set_clientdata(i2c, tc3589x); 394f4e8afdcSSundar Iyer 39520406ebfSSundar Iyer ret = tc3589x_chip_init(tc3589x); 396f4e8afdcSSundar Iyer if (ret) 3971383e00fSJingoo Han return ret; 398f4e8afdcSSundar Iyer 399a435ae1dSLee Jones ret = tc3589x_irq_init(tc3589x, np); 400f4e8afdcSSundar Iyer if (ret) 4011383e00fSJingoo Han return ret; 402f4e8afdcSSundar Iyer 40320406ebfSSundar Iyer ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq, 404f4e8afdcSSundar Iyer IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 40520406ebfSSundar Iyer "tc3589x", tc3589x); 406f4e8afdcSSundar Iyer if (ret) { 40720406ebfSSundar Iyer dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); 4081383e00fSJingoo Han return ret; 409f4e8afdcSSundar Iyer } 410f4e8afdcSSundar Iyer 411611b7590SSundar Iyer ret = tc3589x_device_init(tc3589x); 412f4e8afdcSSundar Iyer if (ret) { 413611b7590SSundar Iyer dev_err(tc3589x->dev, "failed to add child devices\n"); 4141383e00fSJingoo Han return ret; 415f4e8afdcSSundar Iyer } 416f4e8afdcSSundar Iyer 417f4e8afdcSSundar Iyer return 0; 418f4e8afdcSSundar Iyer } 419f4e8afdcSSundar Iyer 4204740f73fSBill Pemberton static int tc3589x_remove(struct i2c_client *client) 421f4e8afdcSSundar Iyer { 42220406ebfSSundar Iyer struct tc3589x *tc3589x = i2c_get_clientdata(client); 423f4e8afdcSSundar Iyer 42420406ebfSSundar Iyer mfd_remove_devices(tc3589x->dev); 425f4e8afdcSSundar Iyer 426f4e8afdcSSundar Iyer return 0; 427f4e8afdcSSundar Iyer } 428f4e8afdcSSundar Iyer 429930bf022SAxel Lin #ifdef CONFIG_PM_SLEEP 430593e9d70SSundar Iyer static int tc3589x_suspend(struct device *dev) 431593e9d70SSundar Iyer { 432593e9d70SSundar Iyer struct tc3589x *tc3589x = dev_get_drvdata(dev); 433593e9d70SSundar Iyer struct i2c_client *client = tc3589x->i2c; 434593e9d70SSundar Iyer int ret = 0; 435593e9d70SSundar Iyer 436593e9d70SSundar Iyer /* put the system to sleep mode */ 437593e9d70SSundar Iyer if (!device_may_wakeup(&client->dev)) 438593e9d70SSundar Iyer ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE, 439593e9d70SSundar Iyer TC3589x_CLKMODE_MODCTL_SLEEP); 440593e9d70SSundar Iyer 441593e9d70SSundar Iyer return ret; 442593e9d70SSundar Iyer } 443593e9d70SSundar Iyer 444593e9d70SSundar Iyer static int tc3589x_resume(struct device *dev) 445593e9d70SSundar Iyer { 446593e9d70SSundar Iyer struct tc3589x *tc3589x = dev_get_drvdata(dev); 447593e9d70SSundar Iyer struct i2c_client *client = tc3589x->i2c; 448593e9d70SSundar Iyer int ret = 0; 449593e9d70SSundar Iyer 450593e9d70SSundar Iyer /* enable the system into operation */ 451593e9d70SSundar Iyer if (!device_may_wakeup(&client->dev)) 452593e9d70SSundar Iyer ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE, 453593e9d70SSundar Iyer TC3589x_CLKMODE_MODCTL_OPERATION); 454593e9d70SSundar Iyer 455593e9d70SSundar Iyer return ret; 456593e9d70SSundar Iyer } 45754d8e2c3SLinus Walleij #endif 458593e9d70SSundar Iyer 459930bf022SAxel Lin static SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend, tc3589x_resume); 460930bf022SAxel Lin 46120406ebfSSundar Iyer static const struct i2c_device_id tc3589x_id[] = { 462*e64c1eb4SLinus Walleij { "tc35890", TC3589X_TC35890 }, 463*e64c1eb4SLinus Walleij { "tc35892", TC3589X_TC35892 }, 464*e64c1eb4SLinus Walleij { "tc35893", TC3589X_TC35893 }, 465*e64c1eb4SLinus Walleij { "tc35894", TC3589X_TC35894 }, 466*e64c1eb4SLinus Walleij { "tc35895", TC3589X_TC35895 }, 467*e64c1eb4SLinus Walleij { "tc35896", TC3589X_TC35896 }, 468*e64c1eb4SLinus Walleij { "tc3589x", TC3589X_UNKNOWN }, 469f4e8afdcSSundar Iyer { } 470f4e8afdcSSundar Iyer }; 47120406ebfSSundar Iyer MODULE_DEVICE_TABLE(i2c, tc3589x_id); 472f4e8afdcSSundar Iyer 47320406ebfSSundar Iyer static struct i2c_driver tc3589x_driver = { 47420406ebfSSundar Iyer .driver.name = "tc3589x", 475f4e8afdcSSundar Iyer .driver.owner = THIS_MODULE, 476593e9d70SSundar Iyer .driver.pm = &tc3589x_dev_pm_ops, 47720406ebfSSundar Iyer .probe = tc3589x_probe, 47884449216SBill Pemberton .remove = tc3589x_remove, 47920406ebfSSundar Iyer .id_table = tc3589x_id, 480f4e8afdcSSundar Iyer }; 481f4e8afdcSSundar Iyer 48220406ebfSSundar Iyer static int __init tc3589x_init(void) 483f4e8afdcSSundar Iyer { 48420406ebfSSundar Iyer return i2c_add_driver(&tc3589x_driver); 485f4e8afdcSSundar Iyer } 48620406ebfSSundar Iyer subsys_initcall(tc3589x_init); 487f4e8afdcSSundar Iyer 48820406ebfSSundar Iyer static void __exit tc3589x_exit(void) 489f4e8afdcSSundar Iyer { 49020406ebfSSundar Iyer i2c_del_driver(&tc3589x_driver); 491f4e8afdcSSundar Iyer } 49220406ebfSSundar Iyer module_exit(tc3589x_exit); 493f4e8afdcSSundar Iyer 494f4e8afdcSSundar Iyer MODULE_LICENSE("GPL v2"); 49520406ebfSSundar Iyer MODULE_DESCRIPTION("TC3589x MFD core driver"); 496f4e8afdcSSundar Iyer MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); 497