13008ddbeSChanwoo Choi /* 23008ddbeSChanwoo Choi * max14577.c - mfd core driver for the Maxim 14577 33008ddbeSChanwoo Choi * 43008ddbeSChanwoo Choi * Copyright (C) 2013 Samsung Electrnoics 53008ddbeSChanwoo Choi * Chanwoo Choi <cw00.choi@samsung.com> 63008ddbeSChanwoo Choi * Krzysztof Kozlowski <k.kozlowski@samsung.com> 73008ddbeSChanwoo Choi * 83008ddbeSChanwoo Choi * This program is free software; you can redistribute it and/or modify 93008ddbeSChanwoo Choi * it under the terms of the GNU General Public License as published by 103008ddbeSChanwoo Choi * the Free Software Foundation; either version 2 of the License, or 113008ddbeSChanwoo Choi * (at your option) any later version. 123008ddbeSChanwoo Choi * 133008ddbeSChanwoo Choi * This program is distributed in the hope that it will be useful, 143008ddbeSChanwoo Choi * but WITHOUT ANY WARRANTY; without even the implied warranty of 153008ddbeSChanwoo Choi * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 163008ddbeSChanwoo Choi * GNU General Public License for more details. 173008ddbeSChanwoo Choi * 183008ddbeSChanwoo Choi * This driver is based on max8997.c 193008ddbeSChanwoo Choi */ 203008ddbeSChanwoo Choi 21c8016d45SSachin Kamat #include <linux/err.h> 223008ddbeSChanwoo Choi #include <linux/module.h> 233008ddbeSChanwoo Choi #include <linux/interrupt.h> 243008ddbeSChanwoo Choi #include <linux/mfd/core.h> 253008ddbeSChanwoo Choi #include <linux/mfd/max14577.h> 263008ddbeSChanwoo Choi #include <linux/mfd/max14577-private.h> 273008ddbeSChanwoo Choi 283008ddbeSChanwoo Choi static struct mfd_cell max14577_devs[] = { 29a0b0ea49SKrzysztof Kozlowski { 30a0b0ea49SKrzysztof Kozlowski .name = "max14577-muic", 31a0b0ea49SKrzysztof Kozlowski .of_compatible = "maxim,max14577-muic", 32a0b0ea49SKrzysztof Kozlowski }, 3341096801SKrzysztof Kozlowski { 3441096801SKrzysztof Kozlowski .name = "max14577-regulator", 3541096801SKrzysztof Kozlowski .of_compatible = "maxim,max14577-regulator", 3641096801SKrzysztof Kozlowski }, 373008ddbeSChanwoo Choi { .name = "max14577-charger", }, 383008ddbeSChanwoo Choi }; 393008ddbeSChanwoo Choi 40575343d1SKrzysztof Kozlowski static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg) 413008ddbeSChanwoo Choi { 423008ddbeSChanwoo Choi switch (reg) { 433008ddbeSChanwoo Choi case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3: 443008ddbeSChanwoo Choi return true; 453008ddbeSChanwoo Choi default: 463008ddbeSChanwoo Choi break; 473008ddbeSChanwoo Choi } 483008ddbeSChanwoo Choi return false; 493008ddbeSChanwoo Choi } 503008ddbeSChanwoo Choi 51575343d1SKrzysztof Kozlowski static const struct regmap_config max14577_muic_regmap_config = { 523008ddbeSChanwoo Choi .reg_bits = 8, 533008ddbeSChanwoo Choi .val_bits = 8, 54575343d1SKrzysztof Kozlowski .volatile_reg = max14577_muic_volatile_reg, 553008ddbeSChanwoo Choi .max_register = MAX14577_REG_END, 563008ddbeSChanwoo Choi }; 573008ddbeSChanwoo Choi 583008ddbeSChanwoo Choi static const struct regmap_irq max14577_irqs[] = { 593008ddbeSChanwoo Choi /* INT1 interrupts */ 603008ddbeSChanwoo Choi { .reg_offset = 0, .mask = INT1_ADC_MASK, }, 613008ddbeSChanwoo Choi { .reg_offset = 0, .mask = INT1_ADCLOW_MASK, }, 623008ddbeSChanwoo Choi { .reg_offset = 0, .mask = INT1_ADCERR_MASK, }, 633008ddbeSChanwoo Choi /* INT2 interrupts */ 643008ddbeSChanwoo Choi { .reg_offset = 1, .mask = INT2_CHGTYP_MASK, }, 653008ddbeSChanwoo Choi { .reg_offset = 1, .mask = INT2_CHGDETRUN_MASK, }, 663008ddbeSChanwoo Choi { .reg_offset = 1, .mask = INT2_DCDTMR_MASK, }, 673008ddbeSChanwoo Choi { .reg_offset = 1, .mask = INT2_DBCHG_MASK, }, 683008ddbeSChanwoo Choi { .reg_offset = 1, .mask = INT2_VBVOLT_MASK, }, 693008ddbeSChanwoo Choi /* INT3 interrupts */ 703008ddbeSChanwoo Choi { .reg_offset = 2, .mask = INT3_EOC_MASK, }, 713008ddbeSChanwoo Choi { .reg_offset = 2, .mask = INT3_CGMBC_MASK, }, 723008ddbeSChanwoo Choi { .reg_offset = 2, .mask = INT3_OVP_MASK, }, 733008ddbeSChanwoo Choi { .reg_offset = 2, .mask = INT3_MBCCHGERR_MASK, }, 743008ddbeSChanwoo Choi }; 753008ddbeSChanwoo Choi 763008ddbeSChanwoo Choi static const struct regmap_irq_chip max14577_irq_chip = { 773008ddbeSChanwoo Choi .name = "max14577", 783008ddbeSChanwoo Choi .status_base = MAX14577_REG_INT1, 793008ddbeSChanwoo Choi .mask_base = MAX14577_REG_INTMASK1, 803008ddbeSChanwoo Choi .mask_invert = 1, 813008ddbeSChanwoo Choi .num_regs = 3, 823008ddbeSChanwoo Choi .irqs = max14577_irqs, 833008ddbeSChanwoo Choi .num_irqs = ARRAY_SIZE(max14577_irqs), 843008ddbeSChanwoo Choi }; 853008ddbeSChanwoo Choi 863008ddbeSChanwoo Choi static int max14577_i2c_probe(struct i2c_client *i2c, 873008ddbeSChanwoo Choi const struct i2c_device_id *id) 883008ddbeSChanwoo Choi { 893008ddbeSChanwoo Choi struct max14577 *max14577; 903008ddbeSChanwoo Choi struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev); 913008ddbeSChanwoo Choi struct device_node *np = i2c->dev.of_node; 923008ddbeSChanwoo Choi u8 reg_data; 933008ddbeSChanwoo Choi int ret = 0; 943008ddbeSChanwoo Choi 953008ddbeSChanwoo Choi if (np) { 963008ddbeSChanwoo Choi pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); 973008ddbeSChanwoo Choi if (!pdata) 983008ddbeSChanwoo Choi return -ENOMEM; 993008ddbeSChanwoo Choi i2c->dev.platform_data = pdata; 1003008ddbeSChanwoo Choi } 1013008ddbeSChanwoo Choi 1023008ddbeSChanwoo Choi if (!pdata) { 103aab5dc68SDan Carpenter dev_err(&i2c->dev, "No platform data found.\n"); 1043008ddbeSChanwoo Choi return -EINVAL; 1053008ddbeSChanwoo Choi } 1063008ddbeSChanwoo Choi 1073008ddbeSChanwoo Choi max14577 = devm_kzalloc(&i2c->dev, sizeof(*max14577), GFP_KERNEL); 1083008ddbeSChanwoo Choi if (!max14577) 1093008ddbeSChanwoo Choi return -ENOMEM; 1103008ddbeSChanwoo Choi 1113008ddbeSChanwoo Choi i2c_set_clientdata(i2c, max14577); 1123008ddbeSChanwoo Choi max14577->dev = &i2c->dev; 1133008ddbeSChanwoo Choi max14577->i2c = i2c; 1143008ddbeSChanwoo Choi max14577->irq = i2c->irq; 1153008ddbeSChanwoo Choi 116575343d1SKrzysztof Kozlowski max14577->regmap = devm_regmap_init_i2c(i2c, 117575343d1SKrzysztof Kozlowski &max14577_muic_regmap_config); 1183008ddbeSChanwoo Choi if (IS_ERR(max14577->regmap)) { 1193008ddbeSChanwoo Choi ret = PTR_ERR(max14577->regmap); 1203008ddbeSChanwoo Choi dev_err(max14577->dev, "Failed to allocate register map: %d\n", 1213008ddbeSChanwoo Choi ret); 1223008ddbeSChanwoo Choi return ret; 1233008ddbeSChanwoo Choi } 1243008ddbeSChanwoo Choi 1253008ddbeSChanwoo Choi ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID, 1263008ddbeSChanwoo Choi ®_data); 1273008ddbeSChanwoo Choi if (ret) { 1283008ddbeSChanwoo Choi dev_err(max14577->dev, "Device not found on this channel: %d\n", 1293008ddbeSChanwoo Choi ret); 1303008ddbeSChanwoo Choi return ret; 1313008ddbeSChanwoo Choi } 1323008ddbeSChanwoo Choi max14577->vendor_id = ((reg_data & DEVID_VENDORID_MASK) >> 1333008ddbeSChanwoo Choi DEVID_VENDORID_SHIFT); 1343008ddbeSChanwoo Choi max14577->device_id = ((reg_data & DEVID_DEVICEID_MASK) >> 1353008ddbeSChanwoo Choi DEVID_DEVICEID_SHIFT); 1363008ddbeSChanwoo Choi dev_info(max14577->dev, "Device ID: 0x%x, vendor: 0x%x\n", 1373008ddbeSChanwoo Choi max14577->device_id, max14577->vendor_id); 1383008ddbeSChanwoo Choi 1393008ddbeSChanwoo Choi ret = regmap_add_irq_chip(max14577->regmap, max14577->irq, 1403008ddbeSChanwoo Choi IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, 1413008ddbeSChanwoo Choi &max14577_irq_chip, 1423008ddbeSChanwoo Choi &max14577->irq_data); 1433008ddbeSChanwoo Choi if (ret != 0) { 1443008ddbeSChanwoo Choi dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", 1453008ddbeSChanwoo Choi max14577->irq, ret); 1463008ddbeSChanwoo Choi return ret; 1473008ddbeSChanwoo Choi } 1483008ddbeSChanwoo Choi 1493008ddbeSChanwoo Choi ret = mfd_add_devices(max14577->dev, -1, max14577_devs, 1503008ddbeSChanwoo Choi ARRAY_SIZE(max14577_devs), NULL, 0, 1513008ddbeSChanwoo Choi regmap_irq_get_domain(max14577->irq_data)); 1523008ddbeSChanwoo Choi if (ret < 0) 1533008ddbeSChanwoo Choi goto err_mfd; 1543008ddbeSChanwoo Choi 1553008ddbeSChanwoo Choi device_init_wakeup(max14577->dev, 1); 1563008ddbeSChanwoo Choi 1573008ddbeSChanwoo Choi return 0; 1583008ddbeSChanwoo Choi 1593008ddbeSChanwoo Choi err_mfd: 1603008ddbeSChanwoo Choi regmap_del_irq_chip(max14577->irq, max14577->irq_data); 1613008ddbeSChanwoo Choi 1623008ddbeSChanwoo Choi return ret; 1633008ddbeSChanwoo Choi } 1643008ddbeSChanwoo Choi 1653008ddbeSChanwoo Choi static int max14577_i2c_remove(struct i2c_client *i2c) 1663008ddbeSChanwoo Choi { 1673008ddbeSChanwoo Choi struct max14577 *max14577 = i2c_get_clientdata(i2c); 1683008ddbeSChanwoo Choi 1693008ddbeSChanwoo Choi mfd_remove_devices(max14577->dev); 1703008ddbeSChanwoo Choi regmap_del_irq_chip(max14577->irq, max14577->irq_data); 1713008ddbeSChanwoo Choi 1723008ddbeSChanwoo Choi return 0; 1733008ddbeSChanwoo Choi } 1743008ddbeSChanwoo Choi 1753008ddbeSChanwoo Choi static const struct i2c_device_id max14577_i2c_id[] = { 1763008ddbeSChanwoo Choi { "max14577", 0 }, 1773008ddbeSChanwoo Choi { } 1783008ddbeSChanwoo Choi }; 1793008ddbeSChanwoo Choi MODULE_DEVICE_TABLE(i2c, max14577_i2c_id); 1803008ddbeSChanwoo Choi 1813edeb1e4SGeert Uytterhoeven #ifdef CONFIG_PM_SLEEP 1823008ddbeSChanwoo Choi static int max14577_suspend(struct device *dev) 1833008ddbeSChanwoo Choi { 1843008ddbeSChanwoo Choi struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 1853008ddbeSChanwoo Choi struct max14577 *max14577 = i2c_get_clientdata(i2c); 1863008ddbeSChanwoo Choi 1873008ddbeSChanwoo Choi if (device_may_wakeup(dev)) { 1883008ddbeSChanwoo Choi enable_irq_wake(max14577->irq); 1893008ddbeSChanwoo Choi /* 1903008ddbeSChanwoo Choi * MUIC IRQ must be disabled during suspend if this is 1913008ddbeSChanwoo Choi * a wake up source because it will be handled before 1923008ddbeSChanwoo Choi * resuming I2C. 1933008ddbeSChanwoo Choi * 1943008ddbeSChanwoo Choi * When device is woken up from suspend (e.g. by ADC change), 1953008ddbeSChanwoo Choi * an interrupt occurs before resuming I2C bus controller. 1963008ddbeSChanwoo Choi * Interrupt handler tries to read registers but this read 1973008ddbeSChanwoo Choi * will fail because I2C is still suspended. 1983008ddbeSChanwoo Choi */ 1993008ddbeSChanwoo Choi disable_irq(max14577->irq); 2003008ddbeSChanwoo Choi } 2013008ddbeSChanwoo Choi 2023008ddbeSChanwoo Choi return 0; 2033008ddbeSChanwoo Choi } 2043008ddbeSChanwoo Choi 2053008ddbeSChanwoo Choi static int max14577_resume(struct device *dev) 2063008ddbeSChanwoo Choi { 2073008ddbeSChanwoo Choi struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); 2083008ddbeSChanwoo Choi struct max14577 *max14577 = i2c_get_clientdata(i2c); 2093008ddbeSChanwoo Choi 2103008ddbeSChanwoo Choi if (device_may_wakeup(dev)) { 2113008ddbeSChanwoo Choi disable_irq_wake(max14577->irq); 2123008ddbeSChanwoo Choi enable_irq(max14577->irq); 2133008ddbeSChanwoo Choi } 2143008ddbeSChanwoo Choi 2153008ddbeSChanwoo Choi return 0; 2163008ddbeSChanwoo Choi } 2173edeb1e4SGeert Uytterhoeven #endif /* CONFIG_PM_SLEEP */ 2183008ddbeSChanwoo Choi 2193008ddbeSChanwoo Choi static struct of_device_id max14577_dt_match[] = { 2203008ddbeSChanwoo Choi { .compatible = "maxim,max14577", }, 2213008ddbeSChanwoo Choi {}, 2223008ddbeSChanwoo Choi }; 2233008ddbeSChanwoo Choi 2243008ddbeSChanwoo Choi static SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume); 2253008ddbeSChanwoo Choi 2263008ddbeSChanwoo Choi static struct i2c_driver max14577_i2c_driver = { 2273008ddbeSChanwoo Choi .driver = { 2283008ddbeSChanwoo Choi .name = "max14577", 2293008ddbeSChanwoo Choi .owner = THIS_MODULE, 2303008ddbeSChanwoo Choi .pm = &max14577_pm, 231ae679c12SSachin Kamat .of_match_table = max14577_dt_match, 2323008ddbeSChanwoo Choi }, 2333008ddbeSChanwoo Choi .probe = max14577_i2c_probe, 2343008ddbeSChanwoo Choi .remove = max14577_i2c_remove, 2353008ddbeSChanwoo Choi .id_table = max14577_i2c_id, 2363008ddbeSChanwoo Choi }; 2373008ddbeSChanwoo Choi 2383008ddbeSChanwoo Choi static int __init max14577_i2c_init(void) 2393008ddbeSChanwoo Choi { 2403008ddbeSChanwoo Choi return i2c_add_driver(&max14577_i2c_driver); 2413008ddbeSChanwoo Choi } 2423008ddbeSChanwoo Choi subsys_initcall(max14577_i2c_init); 2433008ddbeSChanwoo Choi 2443008ddbeSChanwoo Choi static void __exit max14577_i2c_exit(void) 2453008ddbeSChanwoo Choi { 2463008ddbeSChanwoo Choi i2c_del_driver(&max14577_i2c_driver); 2473008ddbeSChanwoo Choi } 2483008ddbeSChanwoo Choi module_exit(max14577_i2c_exit); 2493008ddbeSChanwoo Choi 2503008ddbeSChanwoo Choi MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>"); 2513008ddbeSChanwoo Choi MODULE_DESCRIPTION("MAXIM 14577 multi-function core driver"); 2523008ddbeSChanwoo Choi MODULE_LICENSE("GPL"); 253