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/gpio.h> 2327c6750eSGraeme Gregory #include <linux/mfd/core.h> 24dc9913a0SLaxman Dewangan #include <linux/regmap.h> 2527c6750eSGraeme Gregory #include <linux/mfd/tps65910.h> 26*cd4209ceSRhyland Klein #include <linux/of_device.h> 2727c6750eSGraeme Gregory 2827c6750eSGraeme Gregory static struct mfd_cell tps65910s[] = { 2927c6750eSGraeme Gregory { 3027c6750eSGraeme Gregory .name = "tps65910-pmic", 3127c6750eSGraeme Gregory }, 3227c6750eSGraeme Gregory { 3327c6750eSGraeme Gregory .name = "tps65910-rtc", 3427c6750eSGraeme Gregory }, 3527c6750eSGraeme Gregory { 3627c6750eSGraeme Gregory .name = "tps65910-power", 3727c6750eSGraeme Gregory }, 3827c6750eSGraeme Gregory }; 3927c6750eSGraeme Gregory 4027c6750eSGraeme Gregory 41dc9913a0SLaxman Dewangan static bool is_volatile_reg(struct device *dev, unsigned int reg) 42dc9913a0SLaxman Dewangan { 43dc9913a0SLaxman Dewangan struct tps65910 *tps65910 = dev_get_drvdata(dev); 44dc9913a0SLaxman Dewangan 45dc9913a0SLaxman Dewangan /* 46dc9913a0SLaxman Dewangan * Caching all regulator registers. 47dc9913a0SLaxman Dewangan * All regualator register address range is same for 48dc9913a0SLaxman Dewangan * TPS65910 and TPS65911 49dc9913a0SLaxman Dewangan */ 50dc9913a0SLaxman Dewangan if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) { 51dc9913a0SLaxman Dewangan /* Check for non-existing register */ 52dc9913a0SLaxman Dewangan if (tps65910_chip_id(tps65910) == TPS65910) 53dc9913a0SLaxman Dewangan if ((reg == TPS65911_VDDCTRL_OP) || 54dc9913a0SLaxman Dewangan (reg == TPS65911_VDDCTRL_SR)) 55dc9913a0SLaxman Dewangan return true; 56dc9913a0SLaxman Dewangan return false; 57dc9913a0SLaxman Dewangan } 58dc9913a0SLaxman Dewangan return true; 59dc9913a0SLaxman Dewangan } 60dc9913a0SLaxman Dewangan 6139ecb037SLaxman Dewangan static const struct regmap_config tps65910_regmap_config = { 62dc9913a0SLaxman Dewangan .reg_bits = 8, 63dc9913a0SLaxman Dewangan .val_bits = 8, 64dc9913a0SLaxman Dewangan .volatile_reg = is_volatile_reg, 65dc9913a0SLaxman Dewangan .max_register = TPS65910_MAX_REGISTER, 66dc9913a0SLaxman Dewangan .num_reg_defaults_raw = TPS65910_MAX_REGISTER, 67dc9913a0SLaxman Dewangan .cache_type = REGCACHE_RBTREE, 68dc9913a0SLaxman Dewangan }; 69dc9913a0SLaxman Dewangan 7063745d40SMark Brown static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, 71201cf052SLaxman Dewangan struct tps65910_board *pmic_pdata) 72201cf052SLaxman Dewangan { 73201cf052SLaxman Dewangan struct device *dev = NULL; 74201cf052SLaxman Dewangan int ret = 0; 75201cf052SLaxman Dewangan 76201cf052SLaxman Dewangan dev = tps65910->dev; 77201cf052SLaxman Dewangan 78201cf052SLaxman Dewangan if (!pmic_pdata->en_dev_slp) 79201cf052SLaxman Dewangan return 0; 80201cf052SLaxman Dewangan 81201cf052SLaxman Dewangan /* enabling SLEEP device state */ 823f7e8275SRhyland Klein ret = tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL, 83201cf052SLaxman Dewangan DEVCTRL_DEV_SLP_MASK); 84201cf052SLaxman Dewangan if (ret < 0) { 85201cf052SLaxman Dewangan dev_err(dev, "set dev_slp failed: %d\n", ret); 86201cf052SLaxman Dewangan goto err_sleep_init; 87201cf052SLaxman Dewangan } 88201cf052SLaxman Dewangan 89201cf052SLaxman Dewangan /* Return if there is no sleep keepon data. */ 90201cf052SLaxman Dewangan if (!pmic_pdata->slp_keepon) 91201cf052SLaxman Dewangan return 0; 92201cf052SLaxman Dewangan 93201cf052SLaxman Dewangan if (pmic_pdata->slp_keepon->therm_keepon) { 943f7e8275SRhyland Klein ret = tps65910_reg_set_bits(tps65910, 953f7e8275SRhyland Klein TPS65910_SLEEP_KEEP_RES_ON, 96201cf052SLaxman Dewangan SLEEP_KEEP_RES_ON_THERM_KEEPON_MASK); 97201cf052SLaxman Dewangan if (ret < 0) { 98201cf052SLaxman Dewangan dev_err(dev, "set therm_keepon failed: %d\n", ret); 99201cf052SLaxman Dewangan goto disable_dev_slp; 100201cf052SLaxman Dewangan } 101201cf052SLaxman Dewangan } 102201cf052SLaxman Dewangan 103201cf052SLaxman Dewangan if (pmic_pdata->slp_keepon->clkout32k_keepon) { 1043f7e8275SRhyland Klein ret = tps65910_reg_set_bits(tps65910, 1053f7e8275SRhyland Klein TPS65910_SLEEP_KEEP_RES_ON, 106201cf052SLaxman Dewangan SLEEP_KEEP_RES_ON_CLKOUT32K_KEEPON_MASK); 107201cf052SLaxman Dewangan if (ret < 0) { 108201cf052SLaxman Dewangan dev_err(dev, "set clkout32k_keepon failed: %d\n", ret); 109201cf052SLaxman Dewangan goto disable_dev_slp; 110201cf052SLaxman Dewangan } 111201cf052SLaxman Dewangan } 112201cf052SLaxman Dewangan 113201cf052SLaxman Dewangan if (pmic_pdata->slp_keepon->i2chs_keepon) { 1143f7e8275SRhyland Klein ret = tps65910_reg_set_bits(tps65910, 1153f7e8275SRhyland Klein TPS65910_SLEEP_KEEP_RES_ON, 116201cf052SLaxman Dewangan SLEEP_KEEP_RES_ON_I2CHS_KEEPON_MASK); 117201cf052SLaxman Dewangan if (ret < 0) { 118201cf052SLaxman Dewangan dev_err(dev, "set i2chs_keepon failed: %d\n", ret); 119201cf052SLaxman Dewangan goto disable_dev_slp; 120201cf052SLaxman Dewangan } 121201cf052SLaxman Dewangan } 122201cf052SLaxman Dewangan 123201cf052SLaxman Dewangan return 0; 124201cf052SLaxman Dewangan 125201cf052SLaxman Dewangan disable_dev_slp: 1263f7e8275SRhyland Klein tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL, 1273f7e8275SRhyland Klein DEVCTRL_DEV_SLP_MASK); 128201cf052SLaxman Dewangan 129201cf052SLaxman Dewangan err_sleep_init: 130201cf052SLaxman Dewangan return ret; 131201cf052SLaxman Dewangan } 132201cf052SLaxman Dewangan 133*cd4209ceSRhyland Klein #ifdef CONFIG_OF 134*cd4209ceSRhyland Klein static struct of_device_id tps65910_of_match[] = { 135*cd4209ceSRhyland Klein { .compatible = "ti,tps65910", .data = (void *)TPS65910}, 136*cd4209ceSRhyland Klein { .compatible = "ti,tps65911", .data = (void *)TPS65911}, 137*cd4209ceSRhyland Klein { }, 138*cd4209ceSRhyland Klein }; 139*cd4209ceSRhyland Klein MODULE_DEVICE_TABLE(of, tps65910_of_match); 140*cd4209ceSRhyland Klein 141*cd4209ceSRhyland Klein static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, 142*cd4209ceSRhyland Klein int *chip_id) 143*cd4209ceSRhyland Klein { 144*cd4209ceSRhyland Klein struct device_node *np = client->dev.of_node; 145*cd4209ceSRhyland Klein struct tps65910_board *board_info; 146*cd4209ceSRhyland Klein unsigned int prop; 147*cd4209ceSRhyland Klein const struct of_device_id *match; 148*cd4209ceSRhyland Klein unsigned int prop_array[TPS6591X_MAX_NUM_GPIO]; 149*cd4209ceSRhyland Klein int ret = 0; 150*cd4209ceSRhyland Klein int idx; 151*cd4209ceSRhyland Klein 152*cd4209ceSRhyland Klein match = of_match_device(tps65910_of_match, &client->dev); 153*cd4209ceSRhyland Klein if (!match) { 154*cd4209ceSRhyland Klein dev_err(&client->dev, "Failed to find matching dt id\n"); 155*cd4209ceSRhyland Klein return NULL; 156*cd4209ceSRhyland Klein } 157*cd4209ceSRhyland Klein 158*cd4209ceSRhyland Klein *chip_id = (int)match->data; 159*cd4209ceSRhyland Klein 160*cd4209ceSRhyland Klein board_info = devm_kzalloc(&client->dev, sizeof(*board_info), 161*cd4209ceSRhyland Klein GFP_KERNEL); 162*cd4209ceSRhyland Klein if (!board_info) { 163*cd4209ceSRhyland Klein dev_err(&client->dev, "Failed to allocate pdata\n"); 164*cd4209ceSRhyland Klein return NULL; 165*cd4209ceSRhyland Klein } 166*cd4209ceSRhyland Klein 167*cd4209ceSRhyland Klein ret = of_property_read_u32(np, "ti,vmbch-threshold", &prop); 168*cd4209ceSRhyland Klein if (!ret) 169*cd4209ceSRhyland Klein board_info->vmbch_threshold = prop; 170*cd4209ceSRhyland Klein else if (*chip_id == TPS65911) 171*cd4209ceSRhyland Klein dev_warn(&client->dev, "VMBCH-Threshold not specified"); 172*cd4209ceSRhyland Klein 173*cd4209ceSRhyland Klein ret = of_property_read_u32(np, "ti,vmbch2-threshold", &prop); 174*cd4209ceSRhyland Klein if (!ret) 175*cd4209ceSRhyland Klein board_info->vmbch2_threshold = prop; 176*cd4209ceSRhyland Klein else if (*chip_id == TPS65911) 177*cd4209ceSRhyland Klein dev_warn(&client->dev, "VMBCH2-Threshold not specified"); 178*cd4209ceSRhyland Klein 179*cd4209ceSRhyland Klein ret = of_property_read_u32_array(np, "ti,en-gpio-sleep", 180*cd4209ceSRhyland Klein prop_array, TPS6591X_MAX_NUM_GPIO); 181*cd4209ceSRhyland Klein if (!ret) 182*cd4209ceSRhyland Klein for (idx = 0; idx < ARRAY_SIZE(prop_array); idx++) 183*cd4209ceSRhyland Klein board_info->en_gpio_sleep[idx] = (prop_array[idx] != 0); 184*cd4209ceSRhyland Klein else if (ret != -EINVAL) { 185*cd4209ceSRhyland Klein dev_err(&client->dev, 186*cd4209ceSRhyland Klein "error reading property ti,en-gpio-sleep: %d\n.", ret); 187*cd4209ceSRhyland Klein return NULL; 188*cd4209ceSRhyland Klein } 189*cd4209ceSRhyland Klein 190*cd4209ceSRhyland Klein 191*cd4209ceSRhyland Klein board_info->irq = client->irq; 192*cd4209ceSRhyland Klein board_info->irq_base = -1; 193*cd4209ceSRhyland Klein board_info->gpio_base = -1; 194*cd4209ceSRhyland Klein 195*cd4209ceSRhyland Klein return board_info; 196*cd4209ceSRhyland Klein } 197*cd4209ceSRhyland Klein #else 198*cd4209ceSRhyland Klein static inline struct tps65910_board *tps65910_parse_dt( 199*cd4209ceSRhyland Klein struct i2c_client *client) 200*cd4209ceSRhyland Klein { 201*cd4209ceSRhyland Klein return NULL; 202*cd4209ceSRhyland Klein } 203*cd4209ceSRhyland Klein #endif 204201cf052SLaxman Dewangan 20563745d40SMark Brown static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, 20627c6750eSGraeme Gregory const struct i2c_device_id *id) 20727c6750eSGraeme Gregory { 20827c6750eSGraeme Gregory struct tps65910 *tps65910; 2092537df72SGraeme Gregory struct tps65910_board *pmic_plat_data; 210e3471bdcSGraeme Gregory struct tps65910_platform_data *init_data; 21127c6750eSGraeme Gregory int ret = 0; 212*cd4209ceSRhyland Klein int chip_id = id->driver_data; 21327c6750eSGraeme Gregory 2142537df72SGraeme Gregory pmic_plat_data = dev_get_platdata(&i2c->dev); 215*cd4209ceSRhyland Klein 216*cd4209ceSRhyland Klein if (!pmic_plat_data && i2c->dev.of_node) 217*cd4209ceSRhyland Klein pmic_plat_data = tps65910_parse_dt(i2c, &chip_id); 218*cd4209ceSRhyland Klein 2192537df72SGraeme Gregory if (!pmic_plat_data) 2202537df72SGraeme Gregory return -EINVAL; 2212537df72SGraeme Gregory 222e3471bdcSGraeme Gregory init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL); 223e3471bdcSGraeme Gregory if (init_data == NULL) 224e3471bdcSGraeme Gregory return -ENOMEM; 225e3471bdcSGraeme Gregory 22627c6750eSGraeme Gregory tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL); 227dc7e412dSJesper Juhl if (tps65910 == NULL) { 228dc7e412dSJesper Juhl kfree(init_data); 22927c6750eSGraeme Gregory return -ENOMEM; 230dc7e412dSJesper Juhl } 23127c6750eSGraeme Gregory 23227c6750eSGraeme Gregory i2c_set_clientdata(i2c, tps65910); 23327c6750eSGraeme Gregory tps65910->dev = &i2c->dev; 23427c6750eSGraeme Gregory tps65910->i2c_client = i2c; 235*cd4209ceSRhyland Klein tps65910->id = chip_id; 23627c6750eSGraeme Gregory mutex_init(&tps65910->io_mutex); 23727c6750eSGraeme Gregory 23839ecb037SLaxman Dewangan tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config); 239dc9913a0SLaxman Dewangan if (IS_ERR(tps65910->regmap)) { 240dc9913a0SLaxman Dewangan ret = PTR_ERR(tps65910->regmap); 241dc9913a0SLaxman Dewangan dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret); 242dc9913a0SLaxman Dewangan goto regmap_err; 243dc9913a0SLaxman Dewangan } 244dc9913a0SLaxman Dewangan 24527c6750eSGraeme Gregory ret = mfd_add_devices(tps65910->dev, -1, 24627c6750eSGraeme Gregory tps65910s, ARRAY_SIZE(tps65910s), 24727c6750eSGraeme Gregory NULL, 0); 24827c6750eSGraeme Gregory if (ret < 0) 24927c6750eSGraeme Gregory goto err; 25027c6750eSGraeme Gregory 251b1224cd1SJesper Juhl init_data->irq = pmic_plat_data->irq; 2521773140fSLaxman Dewangan init_data->irq_base = pmic_plat_data->irq_base; 253b1224cd1SJesper Juhl 2542537df72SGraeme Gregory tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base); 2552537df72SGraeme Gregory 2561e351a95SAfzal Mohammed tps65910_irq_init(tps65910, init_data->irq, init_data); 257e3471bdcSGraeme Gregory 258201cf052SLaxman Dewangan tps65910_sleepinit(tps65910, pmic_plat_data); 259201cf052SLaxman Dewangan 260dc7e412dSJesper Juhl kfree(init_data); 26127c6750eSGraeme Gregory return ret; 26227c6750eSGraeme Gregory 26327c6750eSGraeme Gregory err: 264dc9913a0SLaxman Dewangan regmap_exit(tps65910->regmap); 265dc9913a0SLaxman Dewangan regmap_err: 26627c6750eSGraeme Gregory kfree(tps65910); 267dc7e412dSJesper Juhl kfree(init_data); 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); 277dc9913a0SLaxman Dewangan regmap_exit(tps65910->regmap); 27827c6750eSGraeme Gregory kfree(tps65910); 27927c6750eSGraeme Gregory 28027c6750eSGraeme Gregory return 0; 28127c6750eSGraeme Gregory } 28227c6750eSGraeme Gregory 28327c6750eSGraeme Gregory static const struct i2c_device_id tps65910_i2c_id[] = { 28479557056SJorge Eduardo Candelaria { "tps65910", TPS65910 }, 28579557056SJorge Eduardo Candelaria { "tps65911", TPS65911 }, 28627c6750eSGraeme Gregory { } 28727c6750eSGraeme Gregory }; 28827c6750eSGraeme Gregory MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id); 28927c6750eSGraeme Gregory 29027c6750eSGraeme Gregory 29127c6750eSGraeme Gregory static struct i2c_driver tps65910_i2c_driver = { 29227c6750eSGraeme Gregory .driver = { 29327c6750eSGraeme Gregory .name = "tps65910", 29427c6750eSGraeme Gregory .owner = THIS_MODULE, 295*cd4209ceSRhyland Klein .of_match_table = of_match_ptr(tps65910_of_match), 29627c6750eSGraeme Gregory }, 29727c6750eSGraeme Gregory .probe = tps65910_i2c_probe, 29863745d40SMark Brown .remove = __devexit_p(tps65910_i2c_remove), 29927c6750eSGraeme Gregory .id_table = tps65910_i2c_id, 30027c6750eSGraeme Gregory }; 30127c6750eSGraeme Gregory 30227c6750eSGraeme Gregory static int __init tps65910_i2c_init(void) 30327c6750eSGraeme Gregory { 30427c6750eSGraeme Gregory return i2c_add_driver(&tps65910_i2c_driver); 30527c6750eSGraeme Gregory } 30627c6750eSGraeme Gregory /* init early so consumer devices can complete system boot */ 30727c6750eSGraeme Gregory subsys_initcall(tps65910_i2c_init); 30827c6750eSGraeme Gregory 30927c6750eSGraeme Gregory static void __exit tps65910_i2c_exit(void) 31027c6750eSGraeme Gregory { 31127c6750eSGraeme Gregory i2c_del_driver(&tps65910_i2c_driver); 31227c6750eSGraeme Gregory } 31327c6750eSGraeme Gregory module_exit(tps65910_i2c_exit); 31427c6750eSGraeme Gregory 31527c6750eSGraeme Gregory MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); 31627c6750eSGraeme Gregory MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>"); 31727c6750eSGraeme Gregory MODULE_DESCRIPTION("TPS6591x chip family multi-function driver"); 31827c6750eSGraeme Gregory MODULE_LICENSE("GPL"); 319