127c6750eSGraeme Gregory /* 227c6750eSGraeme Gregory * tps65910.c -- TI TPS6591x 327c6750eSGraeme Gregory * 427c6750eSGraeme Gregory * Copyright 2010 Texas Instruments Inc. 527c6750eSGraeme Gregory * 627c6750eSGraeme Gregory * Author: Graeme Gregory <gg@slimlogic.co.uk> 727c6750eSGraeme Gregory * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> 827c6750eSGraeme Gregory * 927c6750eSGraeme Gregory * This program is free software; you can redistribute it and/or modify it 1027c6750eSGraeme Gregory * under the terms of the GNU General Public License as published by the 1127c6750eSGraeme Gregory * Free Software Foundation; either version 2 of the License, or (at your 1227c6750eSGraeme Gregory * option) any later version. 1327c6750eSGraeme Gregory * 1427c6750eSGraeme Gregory */ 1527c6750eSGraeme Gregory 1627c6750eSGraeme Gregory #include <linux/module.h> 1727c6750eSGraeme Gregory #include <linux/moduleparam.h> 1827c6750eSGraeme Gregory #include <linux/init.h> 19dc9913a0SLaxman Dewangan #include <linux/err.h> 2027c6750eSGraeme Gregory #include <linux/slab.h> 2127c6750eSGraeme Gregory #include <linux/i2c.h> 2227c6750eSGraeme Gregory #include <linux/mfd/core.h> 23dc9913a0SLaxman Dewangan #include <linux/regmap.h> 2427c6750eSGraeme Gregory #include <linux/mfd/tps65910.h> 25cd4209ceSRhyland Klein #include <linux/of_device.h> 2627c6750eSGraeme Gregory 2727c6750eSGraeme Gregory static struct mfd_cell tps65910s[] = { 2827c6750eSGraeme Gregory { 2932df986eSLaxman Dewangan .name = "tps65910-gpio", 3032df986eSLaxman Dewangan }, 3132df986eSLaxman Dewangan { 3227c6750eSGraeme Gregory .name = "tps65910-pmic", 3327c6750eSGraeme Gregory }, 3427c6750eSGraeme Gregory { 3527c6750eSGraeme Gregory .name = "tps65910-rtc", 3627c6750eSGraeme Gregory }, 3727c6750eSGraeme Gregory { 3827c6750eSGraeme Gregory .name = "tps65910-power", 3927c6750eSGraeme Gregory }, 4027c6750eSGraeme Gregory }; 4127c6750eSGraeme Gregory 4227c6750eSGraeme Gregory 43dc9913a0SLaxman Dewangan static bool is_volatile_reg(struct device *dev, unsigned int reg) 44dc9913a0SLaxman Dewangan { 45dc9913a0SLaxman Dewangan struct tps65910 *tps65910 = dev_get_drvdata(dev); 46dc9913a0SLaxman Dewangan 47dc9913a0SLaxman Dewangan /* 48dc9913a0SLaxman Dewangan * Caching all regulator registers. 49dc9913a0SLaxman Dewangan * All regualator register address range is same for 50dc9913a0SLaxman Dewangan * TPS65910 and TPS65911 51dc9913a0SLaxman Dewangan */ 52dc9913a0SLaxman Dewangan if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) { 53dc9913a0SLaxman Dewangan /* Check for non-existing register */ 54dc9913a0SLaxman Dewangan if (tps65910_chip_id(tps65910) == TPS65910) 55dc9913a0SLaxman Dewangan if ((reg == TPS65911_VDDCTRL_OP) || 56dc9913a0SLaxman Dewangan (reg == TPS65911_VDDCTRL_SR)) 57dc9913a0SLaxman Dewangan return true; 58dc9913a0SLaxman Dewangan return false; 59dc9913a0SLaxman Dewangan } 60dc9913a0SLaxman Dewangan return true; 61dc9913a0SLaxman Dewangan } 62dc9913a0SLaxman Dewangan 6339ecb037SLaxman Dewangan static const struct regmap_config tps65910_regmap_config = { 64dc9913a0SLaxman Dewangan .reg_bits = 8, 65dc9913a0SLaxman Dewangan .val_bits = 8, 66dc9913a0SLaxman Dewangan .volatile_reg = is_volatile_reg, 673bf6bf9bSLaxman Dewangan .max_register = TPS65910_MAX_REGISTER - 1, 68dc9913a0SLaxman Dewangan .cache_type = REGCACHE_RBTREE, 69dc9913a0SLaxman Dewangan }; 70dc9913a0SLaxman Dewangan 71*712db99dSJohan Hovold static int __devinit tps65910_misc_init(struct tps65910 *tps65910, 72*712db99dSJohan Hovold struct tps65910_board *pmic_pdata) 73*712db99dSJohan Hovold { 74*712db99dSJohan Hovold struct device *dev = tps65910->dev; 75*712db99dSJohan Hovold int ret; 76*712db99dSJohan Hovold 77*712db99dSJohan Hovold if (pmic_pdata->en_ck32k_xtal) { 78*712db99dSJohan Hovold ret = tps65910_reg_clear_bits(tps65910, 79*712db99dSJohan Hovold TPS65910_DEVCTRL, 80*712db99dSJohan Hovold DEVCTRL_CK32K_CTRL_MASK); 81*712db99dSJohan Hovold if (ret < 0) { 82*712db99dSJohan Hovold dev_err(dev, "clear ck32k_ctrl failed: %d\n", ret); 83*712db99dSJohan Hovold return ret; 84*712db99dSJohan Hovold } 85*712db99dSJohan Hovold } 86*712db99dSJohan Hovold 87*712db99dSJohan Hovold return 0; 88*712db99dSJohan Hovold } 89*712db99dSJohan Hovold 9063745d40SMark Brown static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, 91201cf052SLaxman Dewangan struct tps65910_board *pmic_pdata) 92201cf052SLaxman Dewangan { 93201cf052SLaxman Dewangan struct device *dev = NULL; 94201cf052SLaxman Dewangan int ret = 0; 95201cf052SLaxman Dewangan 96201cf052SLaxman Dewangan dev = tps65910->dev; 97201cf052SLaxman Dewangan 98201cf052SLaxman Dewangan if (!pmic_pdata->en_dev_slp) 99201cf052SLaxman Dewangan return 0; 100201cf052SLaxman Dewangan 101201cf052SLaxman Dewangan /* enabling SLEEP device state */ 1023f7e8275SRhyland Klein ret = tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL, 103201cf052SLaxman Dewangan DEVCTRL_DEV_SLP_MASK); 104201cf052SLaxman Dewangan if (ret < 0) { 105201cf052SLaxman Dewangan dev_err(dev, "set dev_slp failed: %d\n", ret); 106201cf052SLaxman Dewangan goto err_sleep_init; 107201cf052SLaxman Dewangan } 108201cf052SLaxman Dewangan 109201cf052SLaxman Dewangan /* Return if there is no sleep keepon data. */ 110201cf052SLaxman Dewangan if (!pmic_pdata->slp_keepon) 111201cf052SLaxman Dewangan return 0; 112201cf052SLaxman Dewangan 113201cf052SLaxman Dewangan if (pmic_pdata->slp_keepon->therm_keepon) { 1143f7e8275SRhyland Klein ret = tps65910_reg_set_bits(tps65910, 1153f7e8275SRhyland Klein TPS65910_SLEEP_KEEP_RES_ON, 116201cf052SLaxman Dewangan SLEEP_KEEP_RES_ON_THERM_KEEPON_MASK); 117201cf052SLaxman Dewangan if (ret < 0) { 118201cf052SLaxman Dewangan dev_err(dev, "set therm_keepon failed: %d\n", ret); 119201cf052SLaxman Dewangan goto disable_dev_slp; 120201cf052SLaxman Dewangan } 121201cf052SLaxman Dewangan } 122201cf052SLaxman Dewangan 123201cf052SLaxman Dewangan if (pmic_pdata->slp_keepon->clkout32k_keepon) { 1243f7e8275SRhyland Klein ret = tps65910_reg_set_bits(tps65910, 1253f7e8275SRhyland Klein TPS65910_SLEEP_KEEP_RES_ON, 126201cf052SLaxman Dewangan SLEEP_KEEP_RES_ON_CLKOUT32K_KEEPON_MASK); 127201cf052SLaxman Dewangan if (ret < 0) { 128201cf052SLaxman Dewangan dev_err(dev, "set clkout32k_keepon failed: %d\n", ret); 129201cf052SLaxman Dewangan goto disable_dev_slp; 130201cf052SLaxman Dewangan } 131201cf052SLaxman Dewangan } 132201cf052SLaxman Dewangan 133201cf052SLaxman Dewangan if (pmic_pdata->slp_keepon->i2chs_keepon) { 1343f7e8275SRhyland Klein ret = tps65910_reg_set_bits(tps65910, 1353f7e8275SRhyland Klein TPS65910_SLEEP_KEEP_RES_ON, 136201cf052SLaxman Dewangan SLEEP_KEEP_RES_ON_I2CHS_KEEPON_MASK); 137201cf052SLaxman Dewangan if (ret < 0) { 138201cf052SLaxman Dewangan dev_err(dev, "set i2chs_keepon failed: %d\n", ret); 139201cf052SLaxman Dewangan goto disable_dev_slp; 140201cf052SLaxman Dewangan } 141201cf052SLaxman Dewangan } 142201cf052SLaxman Dewangan 143201cf052SLaxman Dewangan return 0; 144201cf052SLaxman Dewangan 145201cf052SLaxman Dewangan disable_dev_slp: 1463f7e8275SRhyland Klein tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL, 1473f7e8275SRhyland Klein DEVCTRL_DEV_SLP_MASK); 148201cf052SLaxman Dewangan 149201cf052SLaxman Dewangan err_sleep_init: 150201cf052SLaxman Dewangan return ret; 151201cf052SLaxman Dewangan } 152201cf052SLaxman Dewangan 153cd4209ceSRhyland Klein #ifdef CONFIG_OF 154cd4209ceSRhyland Klein static struct of_device_id tps65910_of_match[] = { 155cd4209ceSRhyland Klein { .compatible = "ti,tps65910", .data = (void *)TPS65910}, 156cd4209ceSRhyland Klein { .compatible = "ti,tps65911", .data = (void *)TPS65911}, 157cd4209ceSRhyland Klein { }, 158cd4209ceSRhyland Klein }; 159cd4209ceSRhyland Klein MODULE_DEVICE_TABLE(of, tps65910_of_match); 160cd4209ceSRhyland Klein 161cd4209ceSRhyland Klein static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, 162cd4209ceSRhyland Klein int *chip_id) 163cd4209ceSRhyland Klein { 164cd4209ceSRhyland Klein struct device_node *np = client->dev.of_node; 165cd4209ceSRhyland Klein struct tps65910_board *board_info; 166cd4209ceSRhyland Klein unsigned int prop; 167cd4209ceSRhyland Klein const struct of_device_id *match; 168cd4209ceSRhyland Klein int ret = 0; 169cd4209ceSRhyland Klein 170cd4209ceSRhyland Klein match = of_match_device(tps65910_of_match, &client->dev); 171cd4209ceSRhyland Klein if (!match) { 172cd4209ceSRhyland Klein dev_err(&client->dev, "Failed to find matching dt id\n"); 173cd4209ceSRhyland Klein return NULL; 174cd4209ceSRhyland Klein } 175cd4209ceSRhyland Klein 176cd4209ceSRhyland Klein *chip_id = (int)match->data; 177cd4209ceSRhyland Klein 178cd4209ceSRhyland Klein board_info = devm_kzalloc(&client->dev, sizeof(*board_info), 179cd4209ceSRhyland Klein GFP_KERNEL); 180cd4209ceSRhyland Klein if (!board_info) { 181cd4209ceSRhyland Klein dev_err(&client->dev, "Failed to allocate pdata\n"); 182cd4209ceSRhyland Klein return NULL; 183cd4209ceSRhyland Klein } 184cd4209ceSRhyland Klein 185cd4209ceSRhyland Klein ret = of_property_read_u32(np, "ti,vmbch-threshold", &prop); 186cd4209ceSRhyland Klein if (!ret) 187cd4209ceSRhyland Klein board_info->vmbch_threshold = prop; 188cd4209ceSRhyland Klein else if (*chip_id == TPS65911) 189cd4209ceSRhyland Klein dev_warn(&client->dev, "VMBCH-Threshold not specified"); 190cd4209ceSRhyland Klein 191cd4209ceSRhyland Klein ret = of_property_read_u32(np, "ti,vmbch2-threshold", &prop); 192cd4209ceSRhyland Klein if (!ret) 193cd4209ceSRhyland Klein board_info->vmbch2_threshold = prop; 194cd4209ceSRhyland Klein else if (*chip_id == TPS65911) 195cd4209ceSRhyland Klein dev_warn(&client->dev, "VMBCH2-Threshold not specified"); 196cd4209ceSRhyland Klein 197cd4209ceSRhyland Klein board_info->irq = client->irq; 198cd4209ceSRhyland Klein board_info->irq_base = -1; 199cd4209ceSRhyland Klein 200cd4209ceSRhyland Klein return board_info; 201cd4209ceSRhyland Klein } 202cd4209ceSRhyland Klein #else 2037f65f74cSSamuel Ortiz static inline 2047f65f74cSSamuel Ortiz struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, 2057f65f74cSSamuel Ortiz int *chip_id) 206cd4209ceSRhyland Klein { 207cd4209ceSRhyland Klein return NULL; 208cd4209ceSRhyland Klein } 209cd4209ceSRhyland Klein #endif 210201cf052SLaxman Dewangan 21163745d40SMark Brown static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, 21227c6750eSGraeme Gregory const struct i2c_device_id *id) 21327c6750eSGraeme Gregory { 21427c6750eSGraeme Gregory struct tps65910 *tps65910; 2152537df72SGraeme Gregory struct tps65910_board *pmic_plat_data; 216cb8d8654SLaxman Dewangan struct tps65910_board *of_pmic_plat_data = NULL; 217e3471bdcSGraeme Gregory struct tps65910_platform_data *init_data; 21827c6750eSGraeme Gregory int ret = 0; 219cd4209ceSRhyland Klein int chip_id = id->driver_data; 22027c6750eSGraeme Gregory 2212537df72SGraeme Gregory pmic_plat_data = dev_get_platdata(&i2c->dev); 222cd4209ceSRhyland Klein 223cb8d8654SLaxman Dewangan if (!pmic_plat_data && i2c->dev.of_node) { 224cd4209ceSRhyland Klein pmic_plat_data = tps65910_parse_dt(i2c, &chip_id); 225cb8d8654SLaxman Dewangan of_pmic_plat_data = pmic_plat_data; 226cb8d8654SLaxman Dewangan } 227cd4209ceSRhyland Klein 2282537df72SGraeme Gregory if (!pmic_plat_data) 2292537df72SGraeme Gregory return -EINVAL; 2302537df72SGraeme Gregory 23163fe7deeSLaxman Dewangan init_data = devm_kzalloc(&i2c->dev, sizeof(*init_data), GFP_KERNEL); 232e3471bdcSGraeme Gregory if (init_data == NULL) 233e3471bdcSGraeme Gregory return -ENOMEM; 234e3471bdcSGraeme Gregory 23563fe7deeSLaxman Dewangan tps65910 = devm_kzalloc(&i2c->dev, sizeof(*tps65910), GFP_KERNEL); 23663fe7deeSLaxman Dewangan if (tps65910 == NULL) 23727c6750eSGraeme Gregory return -ENOMEM; 23827c6750eSGraeme Gregory 239cb8d8654SLaxman Dewangan tps65910->of_plat_data = of_pmic_plat_data; 24027c6750eSGraeme Gregory i2c_set_clientdata(i2c, tps65910); 24127c6750eSGraeme Gregory tps65910->dev = &i2c->dev; 24227c6750eSGraeme Gregory tps65910->i2c_client = i2c; 243cd4209ceSRhyland Klein tps65910->id = chip_id; 24427c6750eSGraeme Gregory mutex_init(&tps65910->io_mutex); 24527c6750eSGraeme Gregory 24663fe7deeSLaxman Dewangan tps65910->regmap = devm_regmap_init_i2c(i2c, &tps65910_regmap_config); 247dc9913a0SLaxman Dewangan if (IS_ERR(tps65910->regmap)) { 248dc9913a0SLaxman Dewangan ret = PTR_ERR(tps65910->regmap); 249dc9913a0SLaxman Dewangan dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret); 25063fe7deeSLaxman Dewangan return ret; 251dc9913a0SLaxman Dewangan } 252dc9913a0SLaxman Dewangan 25327c6750eSGraeme Gregory ret = mfd_add_devices(tps65910->dev, -1, 25427c6750eSGraeme Gregory tps65910s, ARRAY_SIZE(tps65910s), 25527c6750eSGraeme Gregory NULL, 0); 25663fe7deeSLaxman Dewangan if (ret < 0) { 25763fe7deeSLaxman Dewangan dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret); 25863fe7deeSLaxman Dewangan return ret; 25963fe7deeSLaxman Dewangan } 26027c6750eSGraeme Gregory 261b1224cd1SJesper Juhl init_data->irq = pmic_plat_data->irq; 2621773140fSLaxman Dewangan init_data->irq_base = pmic_plat_data->irq_base; 263b1224cd1SJesper Juhl 2641e351a95SAfzal Mohammed tps65910_irq_init(tps65910, init_data->irq, init_data); 265*712db99dSJohan Hovold tps65910_misc_init(tps65910, pmic_plat_data); 266201cf052SLaxman Dewangan tps65910_sleepinit(tps65910, pmic_plat_data); 267201cf052SLaxman Dewangan 26827c6750eSGraeme Gregory return ret; 26927c6750eSGraeme Gregory } 27027c6750eSGraeme Gregory 27163745d40SMark Brown static __devexit int tps65910_i2c_remove(struct i2c_client *i2c) 27227c6750eSGraeme Gregory { 27327c6750eSGraeme Gregory struct tps65910 *tps65910 = i2c_get_clientdata(i2c); 27427c6750eSGraeme Gregory 275ec2328c3SMark Brown tps65910_irq_exit(tps65910); 2761e351a95SAfzal Mohammed mfd_remove_devices(tps65910->dev); 27727c6750eSGraeme Gregory 27827c6750eSGraeme Gregory return 0; 27927c6750eSGraeme Gregory } 28027c6750eSGraeme Gregory 28127c6750eSGraeme Gregory static const struct i2c_device_id tps65910_i2c_id[] = { 28279557056SJorge Eduardo Candelaria { "tps65910", TPS65910 }, 28379557056SJorge Eduardo Candelaria { "tps65911", TPS65911 }, 28427c6750eSGraeme Gregory { } 28527c6750eSGraeme Gregory }; 28627c6750eSGraeme Gregory MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id); 28727c6750eSGraeme Gregory 28827c6750eSGraeme Gregory 28927c6750eSGraeme Gregory static struct i2c_driver tps65910_i2c_driver = { 29027c6750eSGraeme Gregory .driver = { 29127c6750eSGraeme Gregory .name = "tps65910", 29227c6750eSGraeme Gregory .owner = THIS_MODULE, 293cd4209ceSRhyland Klein .of_match_table = of_match_ptr(tps65910_of_match), 29427c6750eSGraeme Gregory }, 29527c6750eSGraeme Gregory .probe = tps65910_i2c_probe, 29663745d40SMark Brown .remove = __devexit_p(tps65910_i2c_remove), 29727c6750eSGraeme Gregory .id_table = tps65910_i2c_id, 29827c6750eSGraeme Gregory }; 29927c6750eSGraeme Gregory 30027c6750eSGraeme Gregory static int __init tps65910_i2c_init(void) 30127c6750eSGraeme Gregory { 30227c6750eSGraeme Gregory return i2c_add_driver(&tps65910_i2c_driver); 30327c6750eSGraeme Gregory } 30427c6750eSGraeme Gregory /* init early so consumer devices can complete system boot */ 30527c6750eSGraeme Gregory subsys_initcall(tps65910_i2c_init); 30627c6750eSGraeme Gregory 30727c6750eSGraeme Gregory static void __exit tps65910_i2c_exit(void) 30827c6750eSGraeme Gregory { 30927c6750eSGraeme Gregory i2c_del_driver(&tps65910_i2c_driver); 31027c6750eSGraeme Gregory } 31127c6750eSGraeme Gregory module_exit(tps65910_i2c_exit); 31227c6750eSGraeme Gregory 31327c6750eSGraeme Gregory MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); 31427c6750eSGraeme Gregory MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>"); 31527c6750eSGraeme Gregory MODULE_DESCRIPTION("TPS6591x chip family multi-function driver"); 31627c6750eSGraeme Gregory MODULE_LICENSE("GPL"); 317