12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 284c99db8SAshish Jangam /* 384c99db8SAshish Jangam * I2C access for DA9052 PMICs. 484c99db8SAshish Jangam * 584c99db8SAshish Jangam * Copyright(c) 2011 Dialog Semiconductor Ltd. 684c99db8SAshish Jangam * 784c99db8SAshish Jangam * Author: David Dajun Chen <dchen@diasemi.com> 884c99db8SAshish Jangam */ 984c99db8SAshish Jangam 1084c99db8SAshish Jangam #include <linux/device.h> 1184c99db8SAshish Jangam #include <linux/module.h> 1284c99db8SAshish Jangam #include <linux/input.h> 1384c99db8SAshish Jangam #include <linux/mfd/core.h> 1484c99db8SAshish Jangam #include <linux/i2c.h> 1584c99db8SAshish Jangam #include <linux/err.h> 1684c99db8SAshish Jangam 1784c99db8SAshish Jangam #include <linux/mfd/da9052/da9052.h> 1884c99db8SAshish Jangam #include <linux/mfd/da9052/reg.h> 1984c99db8SAshish Jangam 2058d114b6SYing-Chun Liu (PaulLiu) #ifdef CONFIG_OF 2158d114b6SYing-Chun Liu (PaulLiu) #include <linux/of.h> 2258d114b6SYing-Chun Liu (PaulLiu) #include <linux/of_device.h> 2358d114b6SYing-Chun Liu (PaulLiu) #endif 2458d114b6SYing-Chun Liu (PaulLiu) 250a8c290aSAshish Jangam /* I2C safe register check */ 260a8c290aSAshish Jangam static inline bool i2c_safe_reg(unsigned char reg) 270a8c290aSAshish Jangam { 280a8c290aSAshish Jangam switch (reg) { 290a8c290aSAshish Jangam case DA9052_STATUS_A_REG: 300a8c290aSAshish Jangam case DA9052_STATUS_B_REG: 310a8c290aSAshish Jangam case DA9052_STATUS_C_REG: 320a8c290aSAshish Jangam case DA9052_STATUS_D_REG: 330a8c290aSAshish Jangam case DA9052_ADC_RES_L_REG: 340a8c290aSAshish Jangam case DA9052_ADC_RES_H_REG: 350a8c290aSAshish Jangam case DA9052_VDD_RES_REG: 360a8c290aSAshish Jangam case DA9052_ICHG_AV_REG: 370a8c290aSAshish Jangam case DA9052_TBAT_RES_REG: 380a8c290aSAshish Jangam case DA9052_ADCIN4_RES_REG: 390a8c290aSAshish Jangam case DA9052_ADCIN5_RES_REG: 400a8c290aSAshish Jangam case DA9052_ADCIN6_RES_REG: 410a8c290aSAshish Jangam case DA9052_TJUNC_RES_REG: 420a8c290aSAshish Jangam case DA9052_TSI_X_MSB_REG: 430a8c290aSAshish Jangam case DA9052_TSI_Y_MSB_REG: 440a8c290aSAshish Jangam case DA9052_TSI_LSB_REG: 450a8c290aSAshish Jangam case DA9052_TSI_Z_MSB_REG: 460a8c290aSAshish Jangam return true; 470a8c290aSAshish Jangam default: 480a8c290aSAshish Jangam return false; 490a8c290aSAshish Jangam } 500a8c290aSAshish Jangam } 510a8c290aSAshish Jangam 520a8c290aSAshish Jangam /* 530a8c290aSAshish Jangam * There is an issue with DA9052 and DA9053_AA/BA/BB PMIC where the PMIC 540a8c290aSAshish Jangam * gets lockup up or fails to respond following a system reset. 550a8c290aSAshish Jangam * This fix is to follow any read or write with a dummy read to a safe 560a8c290aSAshish Jangam * register. 570a8c290aSAshish Jangam */ 58c3e9e6b6SFabio Estevam static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg) 590a8c290aSAshish Jangam { 600a8c290aSAshish Jangam int val; 610a8c290aSAshish Jangam 620a8c290aSAshish Jangam switch (da9052->chip_id) { 630a8c290aSAshish Jangam case DA9052: 640a8c290aSAshish Jangam case DA9053_AA: 650a8c290aSAshish Jangam case DA9053_BA: 660a8c290aSAshish Jangam case DA9053_BB: 670a8c290aSAshish Jangam /* A dummy read to a safe register address. */ 680a8c290aSAshish Jangam if (!i2c_safe_reg(reg)) 690a8c290aSAshish Jangam return regmap_read(da9052->regmap, 700a8c290aSAshish Jangam DA9052_PARK_REGISTER, 710a8c290aSAshish Jangam &val); 720a8c290aSAshish Jangam break; 736c049b2aSOpensource [Anthony Olech] case DA9053_BC: 740a8c290aSAshish Jangam default: 750a8c290aSAshish Jangam /* 760a8c290aSAshish Jangam * For other chips parking of I2C register 770a8c290aSAshish Jangam * to a safe place is not required. 780a8c290aSAshish Jangam */ 790a8c290aSAshish Jangam break; 800a8c290aSAshish Jangam } 810a8c290aSAshish Jangam 820a8c290aSAshish Jangam return 0; 830a8c290aSAshish Jangam } 840a8c290aSAshish Jangam 8543e30f23SDavid Jander /* 8643e30f23SDavid Jander * According to errata item 24, multiwrite mode should be avoided 8743e30f23SDavid Jander * in order to prevent register data corruption after power-down. 8843e30f23SDavid Jander */ 8943e30f23SDavid Jander static int da9052_i2c_disable_multiwrite(struct da9052 *da9052) 9084c99db8SAshish Jangam { 9184c99db8SAshish Jangam int reg_val, ret; 9284c99db8SAshish Jangam 9384c99db8SAshish Jangam ret = regmap_read(da9052->regmap, DA9052_CONTROL_B_REG, ®_val); 9484c99db8SAshish Jangam if (ret < 0) 9584c99db8SAshish Jangam return ret; 9684c99db8SAshish Jangam 9743e30f23SDavid Jander if (!(reg_val & DA9052_CONTROL_B_WRITEMODE)) { 9843e30f23SDavid Jander reg_val |= DA9052_CONTROL_B_WRITEMODE; 9984c99db8SAshish Jangam ret = regmap_write(da9052->regmap, DA9052_CONTROL_B_REG, 10084c99db8SAshish Jangam reg_val); 10184c99db8SAshish Jangam if (ret < 0) 10284c99db8SAshish Jangam return ret; 10384c99db8SAshish Jangam } 10484c99db8SAshish Jangam 10584c99db8SAshish Jangam return 0; 10684c99db8SAshish Jangam } 10784c99db8SAshish Jangam 108e27d650bSArnd Bergmann static const struct i2c_device_id da9052_i2c_id[] = { 10958d114b6SYing-Chun Liu (PaulLiu) {"da9052", DA9052}, 11058d114b6SYing-Chun Liu (PaulLiu) {"da9053-aa", DA9053_AA}, 11158d114b6SYing-Chun Liu (PaulLiu) {"da9053-ba", DA9053_BA}, 11258d114b6SYing-Chun Liu (PaulLiu) {"da9053-bb", DA9053_BB}, 1136c049b2aSOpensource [Anthony Olech] {"da9053-bc", DA9053_BC}, 11458d114b6SYing-Chun Liu (PaulLiu) {} 11558d114b6SYing-Chun Liu (PaulLiu) }; 1164700ef32SZou Wei MODULE_DEVICE_TABLE(i2c, da9052_i2c_id); 11758d114b6SYing-Chun Liu (PaulLiu) 11858d114b6SYing-Chun Liu (PaulLiu) #ifdef CONFIG_OF 11958d114b6SYing-Chun Liu (PaulLiu) static const struct of_device_id dialog_dt_ids[] = { 12058d114b6SYing-Chun Liu (PaulLiu) { .compatible = "dlg,da9052", .data = &da9052_i2c_id[0] }, 12158d114b6SYing-Chun Liu (PaulLiu) { .compatible = "dlg,da9053-aa", .data = &da9052_i2c_id[1] }, 1226c049b2aSOpensource [Anthony Olech] { .compatible = "dlg,da9053-ba", .data = &da9052_i2c_id[2] }, 12358d114b6SYing-Chun Liu (PaulLiu) { .compatible = "dlg,da9053-bb", .data = &da9052_i2c_id[3] }, 1246c049b2aSOpensource [Anthony Olech] { .compatible = "dlg,da9053-bc", .data = &da9052_i2c_id[4] }, 12558d114b6SYing-Chun Liu (PaulLiu) { /* sentinel */ } 12658d114b6SYing-Chun Liu (PaulLiu) }; 12758d114b6SYing-Chun Liu (PaulLiu) #endif 12858d114b6SYing-Chun Liu (PaulLiu) 129f791be49SBill Pemberton static int da9052_i2c_probe(struct i2c_client *client, 13084c99db8SAshish Jangam const struct i2c_device_id *id) 13184c99db8SAshish Jangam { 13284c99db8SAshish Jangam struct da9052 *da9052; 13384c99db8SAshish Jangam int ret; 13484c99db8SAshish Jangam 1356608a5e2SAxel Lin da9052 = devm_kzalloc(&client->dev, sizeof(struct da9052), GFP_KERNEL); 13684c99db8SAshish Jangam if (!da9052) 13784c99db8SAshish Jangam return -ENOMEM; 13884c99db8SAshish Jangam 13984c99db8SAshish Jangam da9052->dev = &client->dev; 14084c99db8SAshish Jangam da9052->chip_irq = client->irq; 1410a8c290aSAshish Jangam da9052->fix_io = da9052_i2c_fix; 14284c99db8SAshish Jangam 14384c99db8SAshish Jangam i2c_set_clientdata(client, da9052); 14484c99db8SAshish Jangam 1456608a5e2SAxel Lin da9052->regmap = devm_regmap_init_i2c(client, &da9052_regmap_config); 14684c99db8SAshish Jangam if (IS_ERR(da9052->regmap)) { 14784c99db8SAshish Jangam ret = PTR_ERR(da9052->regmap); 14884c99db8SAshish Jangam dev_err(&client->dev, "Failed to allocate register map: %d\n", 14984c99db8SAshish Jangam ret); 1506608a5e2SAxel Lin return ret; 15184c99db8SAshish Jangam } 15284c99db8SAshish Jangam 15343e30f23SDavid Jander ret = da9052_i2c_disable_multiwrite(da9052); 15484c99db8SAshish Jangam if (ret < 0) 1556608a5e2SAxel Lin return ret; 15684c99db8SAshish Jangam 15758d114b6SYing-Chun Liu (PaulLiu) #ifdef CONFIG_OF 158*8b201402SKrzysztof Kozlowski if (!id) 159*8b201402SKrzysztof Kozlowski id = of_device_get_match_data(&client->dev); 16058d114b6SYing-Chun Liu (PaulLiu) #endif 16158d114b6SYing-Chun Liu (PaulLiu) 16258d114b6SYing-Chun Liu (PaulLiu) if (!id) { 16358d114b6SYing-Chun Liu (PaulLiu) ret = -ENODEV; 16458d114b6SYing-Chun Liu (PaulLiu) dev_err(&client->dev, "id is null.\n"); 1656608a5e2SAxel Lin return ret; 16658d114b6SYing-Chun Liu (PaulLiu) } 16758d114b6SYing-Chun Liu (PaulLiu) 168ad698ea4SJavier Martinez Canillas return da9052_device_init(da9052, id->driver_data); 16984c99db8SAshish Jangam } 17084c99db8SAshish Jangam 1714740f73fSBill Pemberton static int da9052_i2c_remove(struct i2c_client *client) 17284c99db8SAshish Jangam { 17384c99db8SAshish Jangam struct da9052 *da9052 = i2c_get_clientdata(client); 17484c99db8SAshish Jangam 17584c99db8SAshish Jangam da9052_device_exit(da9052); 17684c99db8SAshish Jangam return 0; 17784c99db8SAshish Jangam } 17884c99db8SAshish Jangam 17984c99db8SAshish Jangam static struct i2c_driver da9052_i2c_driver = { 18084c99db8SAshish Jangam .probe = da9052_i2c_probe, 18184449216SBill Pemberton .remove = da9052_i2c_remove, 18284c99db8SAshish Jangam .id_table = da9052_i2c_id, 18384c99db8SAshish Jangam .driver = { 18484c99db8SAshish Jangam .name = "da9052", 18558d114b6SYing-Chun Liu (PaulLiu) #ifdef CONFIG_OF 18658d114b6SYing-Chun Liu (PaulLiu) .of_match_table = dialog_dt_ids, 18758d114b6SYing-Chun Liu (PaulLiu) #endif 18884c99db8SAshish Jangam }, 18984c99db8SAshish Jangam }; 19084c99db8SAshish Jangam 19184c99db8SAshish Jangam static int __init da9052_i2c_init(void) 19284c99db8SAshish Jangam { 19384c99db8SAshish Jangam int ret; 19484c99db8SAshish Jangam 19584c99db8SAshish Jangam ret = i2c_add_driver(&da9052_i2c_driver); 19684c99db8SAshish Jangam if (ret != 0) { 19784c99db8SAshish Jangam pr_err("DA9052 I2C registration failed %d\n", ret); 19884c99db8SAshish Jangam return ret; 19984c99db8SAshish Jangam } 20084c99db8SAshish Jangam 20184c99db8SAshish Jangam return 0; 20284c99db8SAshish Jangam } 20384c99db8SAshish Jangam subsys_initcall(da9052_i2c_init); 20484c99db8SAshish Jangam 20584c99db8SAshish Jangam static void __exit da9052_i2c_exit(void) 20684c99db8SAshish Jangam { 20784c99db8SAshish Jangam i2c_del_driver(&da9052_i2c_driver); 20884c99db8SAshish Jangam } 20984c99db8SAshish Jangam module_exit(da9052_i2c_exit); 21084c99db8SAshish Jangam 21184c99db8SAshish Jangam MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); 21284c99db8SAshish Jangam MODULE_DESCRIPTION("I2C driver for Dialog DA9052 PMIC"); 21384c99db8SAshish Jangam MODULE_LICENSE("GPL"); 214