0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/irq.h>
0012 #include <linux/irqdomain.h>
0013 #include <linux/slab.h>
0014 #include <linux/i2c.h>
0015 #include <linux/of.h>
0016 #include <linux/of_device.h>
0017 #include <linux/mfd/core.h>
0018 #include <linux/mfd/tc3589x.h>
0019 #include <linux/err.h>
0020
0021
0022
0023
0024 enum tc3589x_version {
0025 TC3589X_TC35890,
0026 TC3589X_TC35892,
0027 TC3589X_TC35893,
0028 TC3589X_TC35894,
0029 TC3589X_TC35895,
0030 TC3589X_TC35896,
0031 TC3589X_UNKNOWN,
0032 };
0033
0034 #define TC3589x_CLKMODE_MODCTL_SLEEP 0x0
0035 #define TC3589x_CLKMODE_MODCTL_OPERATION (1 << 0)
0036
0037
0038
0039
0040
0041
0042 int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg)
0043 {
0044 int ret;
0045
0046 ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg);
0047 if (ret < 0)
0048 dev_err(tc3589x->dev, "failed to read reg %#x: %d\n",
0049 reg, ret);
0050
0051 return ret;
0052 }
0053 EXPORT_SYMBOL_GPL(tc3589x_reg_read);
0054
0055
0056
0057
0058
0059
0060
0061 int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data)
0062 {
0063 int ret;
0064
0065 ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data);
0066 if (ret < 0)
0067 dev_err(tc3589x->dev, "failed to write reg %#x: %d\n",
0068 reg, ret);
0069
0070 return ret;
0071 }
0072 EXPORT_SYMBOL_GPL(tc3589x_reg_write);
0073
0074
0075
0076
0077
0078
0079
0080
0081 int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values)
0082 {
0083 int ret;
0084
0085 ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values);
0086 if (ret < 0)
0087 dev_err(tc3589x->dev, "failed to read regs %#x: %d\n",
0088 reg, ret);
0089
0090 return ret;
0091 }
0092 EXPORT_SYMBOL_GPL(tc3589x_block_read);
0093
0094
0095
0096
0097
0098
0099
0100
0101 int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length,
0102 const u8 *values)
0103 {
0104 int ret;
0105
0106 ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length,
0107 values);
0108 if (ret < 0)
0109 dev_err(tc3589x->dev, "failed to write regs %#x: %d\n",
0110 reg, ret);
0111
0112 return ret;
0113 }
0114 EXPORT_SYMBOL_GPL(tc3589x_block_write);
0115
0116
0117
0118
0119
0120
0121
0122
0123 int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val)
0124 {
0125 int ret;
0126
0127 mutex_lock(&tc3589x->lock);
0128
0129 ret = tc3589x_reg_read(tc3589x, reg);
0130 if (ret < 0)
0131 goto out;
0132
0133 ret &= ~mask;
0134 ret |= val;
0135
0136 ret = tc3589x_reg_write(tc3589x, reg, ret);
0137
0138 out:
0139 mutex_unlock(&tc3589x->lock);
0140 return ret;
0141 }
0142 EXPORT_SYMBOL_GPL(tc3589x_set_bits);
0143
0144 static const struct resource gpio_resources[] = {
0145 {
0146 .start = TC3589x_INT_GPIIRQ,
0147 .end = TC3589x_INT_GPIIRQ,
0148 .flags = IORESOURCE_IRQ,
0149 },
0150 };
0151
0152 static const struct resource keypad_resources[] = {
0153 {
0154 .start = TC3589x_INT_KBDIRQ,
0155 .end = TC3589x_INT_KBDIRQ,
0156 .flags = IORESOURCE_IRQ,
0157 },
0158 };
0159
0160 static const struct mfd_cell tc3589x_dev_gpio[] = {
0161 {
0162 .name = "tc3589x-gpio",
0163 .num_resources = ARRAY_SIZE(gpio_resources),
0164 .resources = &gpio_resources[0],
0165 .of_compatible = "toshiba,tc3589x-gpio",
0166 },
0167 };
0168
0169 static const struct mfd_cell tc3589x_dev_keypad[] = {
0170 {
0171 .name = "tc3589x-keypad",
0172 .num_resources = ARRAY_SIZE(keypad_resources),
0173 .resources = &keypad_resources[0],
0174 .of_compatible = "toshiba,tc3589x-keypad",
0175 },
0176 };
0177
0178 static irqreturn_t tc3589x_irq(int irq, void *data)
0179 {
0180 struct tc3589x *tc3589x = data;
0181 int status;
0182
0183 again:
0184 status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
0185 if (status < 0)
0186 return IRQ_NONE;
0187
0188 while (status) {
0189 int bit = __ffs(status);
0190 int virq = irq_find_mapping(tc3589x->domain, bit);
0191
0192 handle_nested_irq(virq);
0193 status &= ~(1 << bit);
0194 }
0195
0196
0197
0198
0199
0200
0201
0202 status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
0203 if (status)
0204 goto again;
0205
0206 return IRQ_HANDLED;
0207 }
0208
0209 static int tc3589x_irq_map(struct irq_domain *d, unsigned int virq,
0210 irq_hw_number_t hwirq)
0211 {
0212 struct tc3589x *tc3589x = d->host_data;
0213
0214 irq_set_chip_data(virq, tc3589x);
0215 irq_set_chip_and_handler(virq, &dummy_irq_chip,
0216 handle_edge_irq);
0217 irq_set_nested_thread(virq, 1);
0218 irq_set_noprobe(virq);
0219
0220 return 0;
0221 }
0222
0223 static void tc3589x_irq_unmap(struct irq_domain *d, unsigned int virq)
0224 {
0225 irq_set_chip_and_handler(virq, NULL, NULL);
0226 irq_set_chip_data(virq, NULL);
0227 }
0228
0229 static const struct irq_domain_ops tc3589x_irq_ops = {
0230 .map = tc3589x_irq_map,
0231 .unmap = tc3589x_irq_unmap,
0232 .xlate = irq_domain_xlate_onecell,
0233 };
0234
0235 static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np)
0236 {
0237 tc3589x->domain = irq_domain_add_simple(
0238 np, TC3589x_NR_INTERNAL_IRQS, 0,
0239 &tc3589x_irq_ops, tc3589x);
0240
0241 if (!tc3589x->domain) {
0242 dev_err(tc3589x->dev, "Failed to create irqdomain\n");
0243 return -ENOSYS;
0244 }
0245
0246 return 0;
0247 }
0248
0249 static int tc3589x_chip_init(struct tc3589x *tc3589x)
0250 {
0251 int manf, ver, ret;
0252
0253 manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE);
0254 if (manf < 0)
0255 return manf;
0256
0257 ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION);
0258 if (ver < 0)
0259 return ver;
0260
0261 if (manf != TC3589x_MANFCODE_MAGIC) {
0262 dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf);
0263 return -EINVAL;
0264 }
0265
0266 dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x\n", manf, ver);
0267
0268
0269
0270
0271
0272
0273 ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL,
0274 TC3589x_RSTCTRL_TIMRST
0275 | TC3589x_RSTCTRL_ROTRST
0276 | TC3589x_RSTCTRL_KBDRST);
0277 if (ret < 0)
0278 return ret;
0279
0280
0281 return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1);
0282 }
0283
0284 static int tc3589x_device_init(struct tc3589x *tc3589x)
0285 {
0286 int ret = 0;
0287 unsigned int blocks = tc3589x->pdata->block;
0288
0289 if (blocks & TC3589x_BLOCK_GPIO) {
0290 ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
0291 ARRAY_SIZE(tc3589x_dev_gpio), NULL,
0292 0, tc3589x->domain);
0293 if (ret) {
0294 dev_err(tc3589x->dev, "failed to add gpio child\n");
0295 return ret;
0296 }
0297 dev_info(tc3589x->dev, "added gpio block\n");
0298 }
0299
0300 if (blocks & TC3589x_BLOCK_KEYPAD) {
0301 ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad,
0302 ARRAY_SIZE(tc3589x_dev_keypad), NULL,
0303 0, tc3589x->domain);
0304 if (ret) {
0305 dev_err(tc3589x->dev, "failed to keypad child\n");
0306 return ret;
0307 }
0308 dev_info(tc3589x->dev, "added keypad block\n");
0309 }
0310
0311 return ret;
0312 }
0313
0314 static const struct of_device_id tc3589x_match[] = {
0315
0316 { .compatible = "tc3589x", .data = (void *) TC3589X_UNKNOWN },
0317 { .compatible = "toshiba,tc35890", .data = (void *) TC3589X_TC35890 },
0318 { .compatible = "toshiba,tc35892", .data = (void *) TC3589X_TC35892 },
0319 { .compatible = "toshiba,tc35893", .data = (void *) TC3589X_TC35893 },
0320 { .compatible = "toshiba,tc35894", .data = (void *) TC3589X_TC35894 },
0321 { .compatible = "toshiba,tc35895", .data = (void *) TC3589X_TC35895 },
0322 { .compatible = "toshiba,tc35896", .data = (void *) TC3589X_TC35896 },
0323 { }
0324 };
0325
0326 MODULE_DEVICE_TABLE(of, tc3589x_match);
0327
0328 static struct tc3589x_platform_data *
0329 tc3589x_of_probe(struct device *dev, enum tc3589x_version *version)
0330 {
0331 struct device_node *np = dev->of_node;
0332 struct tc3589x_platform_data *pdata;
0333 struct device_node *child;
0334 const struct of_device_id *of_id;
0335
0336 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
0337 if (!pdata)
0338 return ERR_PTR(-ENOMEM);
0339
0340 of_id = of_match_device(tc3589x_match, dev);
0341 if (!of_id)
0342 return ERR_PTR(-ENODEV);
0343 *version = (enum tc3589x_version) of_id->data;
0344
0345 for_each_child_of_node(np, child) {
0346 if (of_device_is_compatible(child, "toshiba,tc3589x-gpio"))
0347 pdata->block |= TC3589x_BLOCK_GPIO;
0348 if (of_device_is_compatible(child, "toshiba,tc3589x-keypad"))
0349 pdata->block |= TC3589x_BLOCK_KEYPAD;
0350 }
0351
0352 return pdata;
0353 }
0354
0355 static int tc3589x_probe(struct i2c_client *i2c,
0356 const struct i2c_device_id *id)
0357 {
0358 struct device_node *np = i2c->dev.of_node;
0359 struct tc3589x_platform_data *pdata = dev_get_platdata(&i2c->dev);
0360 struct tc3589x *tc3589x;
0361 enum tc3589x_version version;
0362 int ret;
0363
0364 if (!pdata) {
0365 pdata = tc3589x_of_probe(&i2c->dev, &version);
0366 if (IS_ERR(pdata)) {
0367 dev_err(&i2c->dev, "No platform data or DT found\n");
0368 return PTR_ERR(pdata);
0369 }
0370 } else {
0371
0372 version = id->driver_data;
0373 }
0374
0375 if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
0376 | I2C_FUNC_SMBUS_I2C_BLOCK))
0377 return -EIO;
0378
0379 tc3589x = devm_kzalloc(&i2c->dev, sizeof(struct tc3589x),
0380 GFP_KERNEL);
0381 if (!tc3589x)
0382 return -ENOMEM;
0383
0384 mutex_init(&tc3589x->lock);
0385
0386 tc3589x->dev = &i2c->dev;
0387 tc3589x->i2c = i2c;
0388 tc3589x->pdata = pdata;
0389
0390 switch (version) {
0391 case TC3589X_TC35893:
0392 case TC3589X_TC35895:
0393 case TC3589X_TC35896:
0394 tc3589x->num_gpio = 20;
0395 break;
0396 case TC3589X_TC35890:
0397 case TC3589X_TC35892:
0398 case TC3589X_TC35894:
0399 case TC3589X_UNKNOWN:
0400 default:
0401 tc3589x->num_gpio = 24;
0402 break;
0403 }
0404
0405 i2c_set_clientdata(i2c, tc3589x);
0406
0407 ret = tc3589x_chip_init(tc3589x);
0408 if (ret)
0409 return ret;
0410
0411 ret = tc3589x_irq_init(tc3589x, np);
0412 if (ret)
0413 return ret;
0414
0415 ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq,
0416 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
0417 "tc3589x", tc3589x);
0418 if (ret) {
0419 dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret);
0420 return ret;
0421 }
0422
0423 ret = tc3589x_device_init(tc3589x);
0424 if (ret) {
0425 dev_err(tc3589x->dev, "failed to add child devices\n");
0426 return ret;
0427 }
0428
0429 return 0;
0430 }
0431
0432 static int tc3589x_remove(struct i2c_client *client)
0433 {
0434 struct tc3589x *tc3589x = i2c_get_clientdata(client);
0435
0436 mfd_remove_devices(tc3589x->dev);
0437
0438 return 0;
0439 }
0440
0441 #ifdef CONFIG_PM_SLEEP
0442 static int tc3589x_suspend(struct device *dev)
0443 {
0444 struct tc3589x *tc3589x = dev_get_drvdata(dev);
0445 struct i2c_client *client = tc3589x->i2c;
0446 int ret = 0;
0447
0448
0449 if (!device_may_wakeup(&client->dev))
0450 ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
0451 TC3589x_CLKMODE_MODCTL_SLEEP);
0452
0453 return ret;
0454 }
0455
0456 static int tc3589x_resume(struct device *dev)
0457 {
0458 struct tc3589x *tc3589x = dev_get_drvdata(dev);
0459 struct i2c_client *client = tc3589x->i2c;
0460 int ret = 0;
0461
0462
0463 if (!device_may_wakeup(&client->dev))
0464 ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
0465 TC3589x_CLKMODE_MODCTL_OPERATION);
0466
0467 return ret;
0468 }
0469 #endif
0470
0471 static SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend, tc3589x_resume);
0472
0473 static const struct i2c_device_id tc3589x_id[] = {
0474 { "tc35890", TC3589X_TC35890 },
0475 { "tc35892", TC3589X_TC35892 },
0476 { "tc35893", TC3589X_TC35893 },
0477 { "tc35894", TC3589X_TC35894 },
0478 { "tc35895", TC3589X_TC35895 },
0479 { "tc35896", TC3589X_TC35896 },
0480 { "tc3589x", TC3589X_UNKNOWN },
0481 { }
0482 };
0483 MODULE_DEVICE_TABLE(i2c, tc3589x_id);
0484
0485 static struct i2c_driver tc3589x_driver = {
0486 .driver = {
0487 .name = "tc3589x",
0488 .pm = &tc3589x_dev_pm_ops,
0489 .of_match_table = of_match_ptr(tc3589x_match),
0490 },
0491 .probe = tc3589x_probe,
0492 .remove = tc3589x_remove,
0493 .id_table = tc3589x_id,
0494 };
0495
0496 static int __init tc3589x_init(void)
0497 {
0498 return i2c_add_driver(&tc3589x_driver);
0499 }
0500 subsys_initcall(tc3589x_init);
0501
0502 static void __exit tc3589x_exit(void)
0503 {
0504 i2c_del_driver(&tc3589x_driver);
0505 }
0506 module_exit(tc3589x_exit);
0507
0508 MODULE_LICENSE("GPL v2");
0509 MODULE_DESCRIPTION("TC3589x MFD core driver");
0510 MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");