diff options
Diffstat (limited to 'drivers/mfd/max8997.c')
| -rw-r--r-- | drivers/mfd/max8997.c | 112 |
1 files changed, 94 insertions, 18 deletions
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index cb83a7ab53e..595364ee178 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -21,8 +21,11 @@ * This driver is based on max8998.c */ +#include <linux/err.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/of.h> +#include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/pm_runtime.h> #include <linux/module.h> @@ -37,7 +40,7 @@ #define I2C_ADDR_RTC (0x0C >> 1) #define I2C_ADDR_HAPTIC (0x90 >> 1) -static struct mfd_cell max8997_devs[] = { +static const struct mfd_cell max8997_devs[] = { { .name = "max8997-pmic", }, { .name = "max8997-rtc", }, { .name = "max8997-battery", }, @@ -47,6 +50,13 @@ static struct mfd_cell max8997_devs[] = { { .name = "max8997-led", .id = 2 }, }; +#ifdef CONFIG_OF +static const struct of_device_id max8997_pmic_dt_match[] = { + { .compatible = "maxim,max8997-pmic", .data = (void *)TYPE_MAX8997 }, + {}, +}; +#endif + int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) { struct max8997_dev *max8997 = i2c_get_clientdata(i2c); @@ -123,54 +133,120 @@ int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) } EXPORT_SYMBOL_GPL(max8997_update_reg); +/* + * Only the common platform data elements for max8997 are parsed here from the + * device tree. Other sub-modules of max8997 such as pmic, rtc and others have + * to parse their own platform data elements from device tree. + * + * The max8997 platform data structure is instantiated here and the drivers for + * the sub-modules need not instantiate another instance while parsing their + * platform data. + */ +static struct max8997_platform_data *max8997_i2c_parse_dt_pdata( + struct device *dev) +{ + struct max8997_platform_data *pd; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) { + dev_err(dev, "could not allocate memory for pdata\n"); + return ERR_PTR(-ENOMEM); + } + + pd->ono = irq_of_parse_and_map(dev->of_node, 1); + + /* + * ToDo: the 'wakeup' member in the platform data is more of a linux + * specfic information. Hence, there is no binding for that yet and + * not parsed here. + */ + + return pd; +} + +static inline unsigned long max8997_i2c_get_driver_data(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(max8997_pmic_dt_match, i2c->dev.of_node); + return (unsigned long)match->data; + } + return id->driver_data; +} + static int max8997_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max8997_dev *max8997; - struct max8997_platform_data *pdata = i2c->dev.platform_data; + struct max8997_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret = 0; - max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL); + max8997 = devm_kzalloc(&i2c->dev, sizeof(struct max8997_dev), + GFP_KERNEL); if (max8997 == NULL) return -ENOMEM; i2c_set_clientdata(i2c, max8997); max8997->dev = &i2c->dev; max8997->i2c = i2c; - max8997->type = id->driver_data; + max8997->type = max8997_i2c_get_driver_data(i2c, id); max8997->irq = i2c->irq; + if (IS_ENABLED(CONFIG_OF) && max8997->dev->of_node) { + pdata = max8997_i2c_parse_dt_pdata(max8997->dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } + if (!pdata) - goto err; + return ret; - max8997->irq_base = pdata->irq_base; + max8997->pdata = pdata; max8997->ono = pdata->ono; mutex_init(&max8997->iolock); max8997->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC); + if (!max8997->rtc) { + dev_err(max8997->dev, "Failed to allocate I2C device for RTC\n"); + return -ENODEV; + } i2c_set_clientdata(max8997->rtc, max8997); + max8997->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); + if (!max8997->haptic) { + dev_err(max8997->dev, "Failed to allocate I2C device for Haptic\n"); + ret = -ENODEV; + goto err_i2c_haptic; + } i2c_set_clientdata(max8997->haptic, max8997); + max8997->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC); + if (!max8997->muic) { + dev_err(max8997->dev, "Failed to allocate I2C device for MUIC\n"); + ret = -ENODEV; + goto err_i2c_muic; + } i2c_set_clientdata(max8997->muic, max8997); pm_runtime_set_active(max8997->dev); max8997_irq_init(max8997); - mfd_add_devices(max8997->dev, -1, max8997_devs, + ret = mfd_add_devices(max8997->dev, -1, max8997_devs, ARRAY_SIZE(max8997_devs), - NULL, 0); + NULL, 0, NULL); + if (ret < 0) { + dev_err(max8997->dev, "failed to add MFD devices %d\n", ret); + goto err_mfd; + } /* * TODO: enable others (flash, muic, rtc, battery, ...) and * check the return value */ - if (ret < 0) - goto err_mfd; - /* MAX8997 has a power button input. */ device_init_wakeup(max8997->dev, pdata->wakeup); @@ -179,10 +255,10 @@ static int max8997_i2c_probe(struct i2c_client *i2c, err_mfd: mfd_remove_devices(max8997->dev); i2c_unregister_device(max8997->muic); +err_i2c_muic: i2c_unregister_device(max8997->haptic); +err_i2c_haptic: i2c_unregister_device(max8997->rtc); -err: - kfree(max8997); return ret; } @@ -194,7 +270,6 @@ static int max8997_i2c_remove(struct i2c_client *i2c) i2c_unregister_device(max8997->muic); i2c_unregister_device(max8997->haptic); i2c_unregister_device(max8997->rtc); - kfree(max8997); return 0; } @@ -206,7 +281,7 @@ static const struct i2c_device_id max8997_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); -u8 max8997_dumpaddr_pmic[] = { +static u8 max8997_dumpaddr_pmic[] = { MAX8997_REG_INT1MSK, MAX8997_REG_INT2MSK, MAX8997_REG_INT3MSK, @@ -331,7 +406,7 @@ u8 max8997_dumpaddr_pmic[] = { MAX8997_REG_DVSOKTIMER5, }; -u8 max8997_dumpaddr_muic[] = { +static u8 max8997_dumpaddr_muic[] = { MAX8997_MUIC_REG_INTMASK1, MAX8997_MUIC_REG_INTMASK2, MAX8997_MUIC_REG_INTMASK3, @@ -341,7 +416,7 @@ u8 max8997_dumpaddr_muic[] = { MAX8997_MUIC_REG_CONTROL3, }; -u8 max8997_dumpaddr_haptic[] = { +static u8 max8997_dumpaddr_haptic[] = { MAX8997_HAPTIC_REG_CONF1, MAX8997_HAPTIC_REG_CONF2, MAX8997_HAPTIC_REG_DRVCONF, @@ -423,7 +498,7 @@ static int max8997_resume(struct device *dev) return max8997_irq_resume(max8997); } -const struct dev_pm_ops max8997_pm = { +static const struct dev_pm_ops max8997_pm = { .suspend = max8997_suspend, .resume = max8997_resume, .freeze = max8997_freeze, @@ -435,6 +510,7 @@ static struct i2c_driver max8997_i2c_driver = { .name = "max8997", .owner = THIS_MODULE, .pm = &max8997_pm, + .of_match_table = of_match_ptr(max8997_pmic_dt_match), }, .probe = max8997_i2c_probe, .remove = max8997_i2c_remove, |
