480 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// max8997.c - mfd core driver for the Maxim 8966 and 89974//5// Copyright (C) 2011 Samsung Electronics6// MyungJoo Ham <myungjoo.ham@samsung.com>7//8// This driver is based on max8998.c9 10#include <linux/err.h>11#include <linux/slab.h>12#include <linux/i2c.h>13#include <linux/of.h>14#include <linux/of_irq.h>15#include <linux/interrupt.h>16#include <linux/pm_runtime.h>17#include <linux/init.h>18#include <linux/mutex.h>19#include <linux/mfd/core.h>20#include <linux/mfd/max8997.h>21#include <linux/mfd/max8997-private.h>22 23#define I2C_ADDR_PMIC (0xCC >> 1)24#define I2C_ADDR_MUIC (0x4A >> 1)25#define I2C_ADDR_BATTERY (0x6C >> 1)26#define I2C_ADDR_RTC (0x0C >> 1)27#define I2C_ADDR_HAPTIC (0x90 >> 1)28 29static const struct mfd_cell max8997_devs[] = {30 { .name = "max8997-pmic", },31 { .name = "max8997-rtc", },32 { .name = "max8997-battery", },33 { .name = "max8997-haptic", },34 { .name = "max8997-muic", },35 { .name = "max8997-led", .id = 1 },36 { .name = "max8997-led", .id = 2 },37};38 39#ifdef CONFIG_OF40static const struct of_device_id max8997_pmic_dt_match[] = {41 { .compatible = "maxim,max8997-pmic", .data = (void *)TYPE_MAX8997 },42 {},43};44#endif45 46int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)47{48 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);49 int ret;50 51 mutex_lock(&max8997->iolock);52 ret = i2c_smbus_read_byte_data(i2c, reg);53 mutex_unlock(&max8997->iolock);54 if (ret < 0)55 return ret;56 57 ret &= 0xff;58 *dest = ret;59 return 0;60}61EXPORT_SYMBOL_GPL(max8997_read_reg);62 63int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf)64{65 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);66 int ret;67 68 mutex_lock(&max8997->iolock);69 ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf);70 mutex_unlock(&max8997->iolock);71 if (ret < 0)72 return ret;73 74 return 0;75}76EXPORT_SYMBOL_GPL(max8997_bulk_read);77 78int max8997_write_reg(struct i2c_client *i2c, u8 reg, u8 value)79{80 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);81 int ret;82 83 mutex_lock(&max8997->iolock);84 ret = i2c_smbus_write_byte_data(i2c, reg, value);85 mutex_unlock(&max8997->iolock);86 return ret;87}88EXPORT_SYMBOL_GPL(max8997_write_reg);89 90int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf)91{92 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);93 int ret;94 95 mutex_lock(&max8997->iolock);96 ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf);97 mutex_unlock(&max8997->iolock);98 if (ret < 0)99 return ret;100 101 return 0;102}103EXPORT_SYMBOL_GPL(max8997_bulk_write);104 105int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)106{107 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);108 int ret;109 110 mutex_lock(&max8997->iolock);111 ret = i2c_smbus_read_byte_data(i2c, reg);112 if (ret >= 0) {113 u8 old_val = ret & 0xff;114 u8 new_val = (val & mask) | (old_val & (~mask));115 ret = i2c_smbus_write_byte_data(i2c, reg, new_val);116 }117 mutex_unlock(&max8997->iolock);118 return ret;119}120EXPORT_SYMBOL_GPL(max8997_update_reg);121 122/*123 * Only the common platform data elements for max8997 are parsed here from the124 * device tree. Other sub-modules of max8997 such as pmic, rtc and others have125 * to parse their own platform data elements from device tree.126 *127 * The max8997 platform data structure is instantiated here and the drivers for128 * the sub-modules need not instantiate another instance while parsing their129 * platform data.130 */131static struct max8997_platform_data *max8997_i2c_parse_dt_pdata(132 struct device *dev)133{134 struct max8997_platform_data *pd;135 136 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);137 if (!pd)138 return ERR_PTR(-ENOMEM);139 140 pd->ono = irq_of_parse_and_map(dev->of_node, 1);141 142 return pd;143}144 145static int max8997_i2c_probe(struct i2c_client *i2c)146{147 struct max8997_dev *max8997;148 struct max8997_platform_data *pdata = dev_get_platdata(&i2c->dev);149 int ret = 0;150 151 max8997 = devm_kzalloc(&i2c->dev, sizeof(struct max8997_dev),152 GFP_KERNEL);153 if (max8997 == NULL)154 return -ENOMEM;155 156 i2c_set_clientdata(i2c, max8997);157 max8997->dev = &i2c->dev;158 max8997->i2c = i2c;159 max8997->type = (uintptr_t)i2c_get_match_data(i2c);160 max8997->irq = i2c->irq;161 162 if (IS_ENABLED(CONFIG_OF) && max8997->dev->of_node) {163 pdata = max8997_i2c_parse_dt_pdata(max8997->dev);164 if (IS_ERR(pdata))165 return PTR_ERR(pdata);166 }167 168 if (!pdata)169 return ret;170 171 max8997->pdata = pdata;172 max8997->ono = pdata->ono;173 174 mutex_init(&max8997->iolock);175 176 max8997->rtc = i2c_new_dummy_device(i2c->adapter, I2C_ADDR_RTC);177 if (IS_ERR(max8997->rtc)) {178 dev_err(max8997->dev, "Failed to allocate I2C device for RTC\n");179 return PTR_ERR(max8997->rtc);180 }181 i2c_set_clientdata(max8997->rtc, max8997);182 183 max8997->haptic = i2c_new_dummy_device(i2c->adapter, I2C_ADDR_HAPTIC);184 if (IS_ERR(max8997->haptic)) {185 dev_err(max8997->dev, "Failed to allocate I2C device for Haptic\n");186 ret = PTR_ERR(max8997->haptic);187 goto err_i2c_haptic;188 }189 i2c_set_clientdata(max8997->haptic, max8997);190 191 max8997->muic = i2c_new_dummy_device(i2c->adapter, I2C_ADDR_MUIC);192 if (IS_ERR(max8997->muic)) {193 dev_err(max8997->dev, "Failed to allocate I2C device for MUIC\n");194 ret = PTR_ERR(max8997->muic);195 goto err_i2c_muic;196 }197 i2c_set_clientdata(max8997->muic, max8997);198 199 pm_runtime_set_active(max8997->dev);200 201 max8997_irq_init(max8997);202 203 ret = mfd_add_devices(max8997->dev, -1, max8997_devs,204 ARRAY_SIZE(max8997_devs),205 NULL, 0, NULL);206 if (ret < 0) {207 dev_err(max8997->dev, "failed to add MFD devices %d\n", ret);208 goto err_mfd;209 }210 211 /*212 * TODO: enable others (flash, muic, rtc, battery, ...) and213 * check the return value214 */215 216 /* MAX8997 has a power button input. */217 device_init_wakeup(max8997->dev, true);218 219 return ret;220 221err_mfd:222 mfd_remove_devices(max8997->dev);223 i2c_unregister_device(max8997->muic);224err_i2c_muic:225 i2c_unregister_device(max8997->haptic);226err_i2c_haptic:227 i2c_unregister_device(max8997->rtc);228 return ret;229}230 231static const struct i2c_device_id max8997_i2c_id[] = {232 { "max8997", TYPE_MAX8997 },233 { "max8966", TYPE_MAX8966 },234 { }235};236 237static u8 max8997_dumpaddr_pmic[] = {238 MAX8997_REG_INT1MSK,239 MAX8997_REG_INT2MSK,240 MAX8997_REG_INT3MSK,241 MAX8997_REG_INT4MSK,242 MAX8997_REG_MAINCON1,243 MAX8997_REG_MAINCON2,244 MAX8997_REG_BUCKRAMP,245 MAX8997_REG_BUCK1CTRL,246 MAX8997_REG_BUCK1DVS1,247 MAX8997_REG_BUCK1DVS2,248 MAX8997_REG_BUCK1DVS3,249 MAX8997_REG_BUCK1DVS4,250 MAX8997_REG_BUCK1DVS5,251 MAX8997_REG_BUCK1DVS6,252 MAX8997_REG_BUCK1DVS7,253 MAX8997_REG_BUCK1DVS8,254 MAX8997_REG_BUCK2CTRL,255 MAX8997_REG_BUCK2DVS1,256 MAX8997_REG_BUCK2DVS2,257 MAX8997_REG_BUCK2DVS3,258 MAX8997_REG_BUCK2DVS4,259 MAX8997_REG_BUCK2DVS5,260 MAX8997_REG_BUCK2DVS6,261 MAX8997_REG_BUCK2DVS7,262 MAX8997_REG_BUCK2DVS8,263 MAX8997_REG_BUCK3CTRL,264 MAX8997_REG_BUCK3DVS,265 MAX8997_REG_BUCK4CTRL,266 MAX8997_REG_BUCK4DVS,267 MAX8997_REG_BUCK5CTRL,268 MAX8997_REG_BUCK5DVS1,269 MAX8997_REG_BUCK5DVS2,270 MAX8997_REG_BUCK5DVS3,271 MAX8997_REG_BUCK5DVS4,272 MAX8997_REG_BUCK5DVS5,273 MAX8997_REG_BUCK5DVS6,274 MAX8997_REG_BUCK5DVS7,275 MAX8997_REG_BUCK5DVS8,276 MAX8997_REG_BUCK6CTRL,277 MAX8997_REG_BUCK6BPSKIPCTRL,278 MAX8997_REG_BUCK7CTRL,279 MAX8997_REG_BUCK7DVS,280 MAX8997_REG_LDO1CTRL,281 MAX8997_REG_LDO2CTRL,282 MAX8997_REG_LDO3CTRL,283 MAX8997_REG_LDO4CTRL,284 MAX8997_REG_LDO5CTRL,285 MAX8997_REG_LDO6CTRL,286 MAX8997_REG_LDO7CTRL,287 MAX8997_REG_LDO8CTRL,288 MAX8997_REG_LDO9CTRL,289 MAX8997_REG_LDO10CTRL,290 MAX8997_REG_LDO11CTRL,291 MAX8997_REG_LDO12CTRL,292 MAX8997_REG_LDO13CTRL,293 MAX8997_REG_LDO14CTRL,294 MAX8997_REG_LDO15CTRL,295 MAX8997_REG_LDO16CTRL,296 MAX8997_REG_LDO17CTRL,297 MAX8997_REG_LDO18CTRL,298 MAX8997_REG_LDO21CTRL,299 MAX8997_REG_MBCCTRL1,300 MAX8997_REG_MBCCTRL2,301 MAX8997_REG_MBCCTRL3,302 MAX8997_REG_MBCCTRL4,303 MAX8997_REG_MBCCTRL5,304 MAX8997_REG_MBCCTRL6,305 MAX8997_REG_OTPCGHCVS,306 MAX8997_REG_SAFEOUTCTRL,307 MAX8997_REG_LBCNFG1,308 MAX8997_REG_LBCNFG2,309 MAX8997_REG_BBCCTRL,310 311 MAX8997_REG_FLASH1_CUR,312 MAX8997_REG_FLASH2_CUR,313 MAX8997_REG_MOVIE_CUR,314 MAX8997_REG_GSMB_CUR,315 MAX8997_REG_BOOST_CNTL,316 MAX8997_REG_LEN_CNTL,317 MAX8997_REG_FLASH_CNTL,318 MAX8997_REG_WDT_CNTL,319 MAX8997_REG_MAXFLASH1,320 MAX8997_REG_MAXFLASH2,321 MAX8997_REG_FLASHSTATUSMASK,322 323 MAX8997_REG_GPIOCNTL1,324 MAX8997_REG_GPIOCNTL2,325 MAX8997_REG_GPIOCNTL3,326 MAX8997_REG_GPIOCNTL4,327 MAX8997_REG_GPIOCNTL5,328 MAX8997_REG_GPIOCNTL6,329 MAX8997_REG_GPIOCNTL7,330 MAX8997_REG_GPIOCNTL8,331 MAX8997_REG_GPIOCNTL9,332 MAX8997_REG_GPIOCNTL10,333 MAX8997_REG_GPIOCNTL11,334 MAX8997_REG_GPIOCNTL12,335 336 MAX8997_REG_LDO1CONFIG,337 MAX8997_REG_LDO2CONFIG,338 MAX8997_REG_LDO3CONFIG,339 MAX8997_REG_LDO4CONFIG,340 MAX8997_REG_LDO5CONFIG,341 MAX8997_REG_LDO6CONFIG,342 MAX8997_REG_LDO7CONFIG,343 MAX8997_REG_LDO8CONFIG,344 MAX8997_REG_LDO9CONFIG,345 MAX8997_REG_LDO10CONFIG,346 MAX8997_REG_LDO11CONFIG,347 MAX8997_REG_LDO12CONFIG,348 MAX8997_REG_LDO13CONFIG,349 MAX8997_REG_LDO14CONFIG,350 MAX8997_REG_LDO15CONFIG,351 MAX8997_REG_LDO16CONFIG,352 MAX8997_REG_LDO17CONFIG,353 MAX8997_REG_LDO18CONFIG,354 MAX8997_REG_LDO21CONFIG,355 356 MAX8997_REG_DVSOKTIMER1,357 MAX8997_REG_DVSOKTIMER2,358 MAX8997_REG_DVSOKTIMER4,359 MAX8997_REG_DVSOKTIMER5,360};361 362static u8 max8997_dumpaddr_muic[] = {363 MAX8997_MUIC_REG_INTMASK1,364 MAX8997_MUIC_REG_INTMASK2,365 MAX8997_MUIC_REG_INTMASK3,366 MAX8997_MUIC_REG_CDETCTRL,367 MAX8997_MUIC_REG_CONTROL1,368 MAX8997_MUIC_REG_CONTROL2,369 MAX8997_MUIC_REG_CONTROL3,370};371 372static u8 max8997_dumpaddr_haptic[] = {373 MAX8997_HAPTIC_REG_CONF1,374 MAX8997_HAPTIC_REG_CONF2,375 MAX8997_HAPTIC_REG_DRVCONF,376 MAX8997_HAPTIC_REG_CYCLECONF1,377 MAX8997_HAPTIC_REG_CYCLECONF2,378 MAX8997_HAPTIC_REG_SIGCONF1,379 MAX8997_HAPTIC_REG_SIGCONF2,380 MAX8997_HAPTIC_REG_SIGCONF3,381 MAX8997_HAPTIC_REG_SIGCONF4,382 MAX8997_HAPTIC_REG_SIGDC1,383 MAX8997_HAPTIC_REG_SIGDC2,384 MAX8997_HAPTIC_REG_SIGPWMDC1,385 MAX8997_HAPTIC_REG_SIGPWMDC2,386 MAX8997_HAPTIC_REG_SIGPWMDC3,387 MAX8997_HAPTIC_REG_SIGPWMDC4,388};389 390static int max8997_freeze(struct device *dev)391{392 struct i2c_client *i2c = to_i2c_client(dev);393 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);394 int i;395 396 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++)397 max8997_read_reg(i2c, max8997_dumpaddr_pmic[i],398 &max8997->reg_dump[i]);399 400 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++)401 max8997_read_reg(i2c, max8997_dumpaddr_muic[i],402 &max8997->reg_dump[i + MAX8997_REG_PMIC_END]);403 404 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++)405 max8997_read_reg(i2c, max8997_dumpaddr_haptic[i],406 &max8997->reg_dump[i + MAX8997_REG_PMIC_END +407 MAX8997_MUIC_REG_END]);408 409 return 0;410}411 412static int max8997_restore(struct device *dev)413{414 struct i2c_client *i2c = to_i2c_client(dev);415 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);416 int i;417 418 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++)419 max8997_write_reg(i2c, max8997_dumpaddr_pmic[i],420 max8997->reg_dump[i]);421 422 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++)423 max8997_write_reg(i2c, max8997_dumpaddr_muic[i],424 max8997->reg_dump[i + MAX8997_REG_PMIC_END]);425 426 for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++)427 max8997_write_reg(i2c, max8997_dumpaddr_haptic[i],428 max8997->reg_dump[i + MAX8997_REG_PMIC_END +429 MAX8997_MUIC_REG_END]);430 431 return 0;432}433 434static int max8997_suspend(struct device *dev)435{436 struct i2c_client *i2c = to_i2c_client(dev);437 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);438 439 disable_irq(max8997->irq);440 if (device_may_wakeup(dev))441 irq_set_irq_wake(max8997->irq, 1);442 return 0;443}444 445static int max8997_resume(struct device *dev)446{447 struct i2c_client *i2c = to_i2c_client(dev);448 struct max8997_dev *max8997 = i2c_get_clientdata(i2c);449 450 if (device_may_wakeup(dev))451 irq_set_irq_wake(max8997->irq, 0);452 enable_irq(max8997->irq);453 return max8997_irq_resume(max8997);454}455 456static const struct dev_pm_ops max8997_pm = {457 .suspend = max8997_suspend,458 .resume = max8997_resume,459 .freeze = max8997_freeze,460 .restore = max8997_restore,461};462 463static struct i2c_driver max8997_i2c_driver = {464 .driver = {465 .name = "max8997",466 .pm = &max8997_pm,467 .suppress_bind_attrs = true,468 .of_match_table = of_match_ptr(max8997_pmic_dt_match),469 },470 .probe = max8997_i2c_probe,471 .id_table = max8997_i2c_id,472};473 474static int __init max8997_i2c_init(void)475{476 return i2c_add_driver(&max8997_i2c_driver);477}478/* init early so consumer devices can complete system boot */479subsys_initcall(max8997_i2c_init);480