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> 2627c6750eSGraeme Gregory 2727c6750eSGraeme Gregory static struct mfd_cell tps65910s[] = { 2827c6750eSGraeme Gregory { 2927c6750eSGraeme Gregory .name = "tps65910-pmic", 3027c6750eSGraeme Gregory }, 3127c6750eSGraeme Gregory { 3227c6750eSGraeme Gregory .name = "tps65910-rtc", 3327c6750eSGraeme Gregory }, 3427c6750eSGraeme Gregory { 3527c6750eSGraeme Gregory .name = "tps65910-power", 3627c6750eSGraeme Gregory }, 3727c6750eSGraeme Gregory }; 3827c6750eSGraeme Gregory 3927c6750eSGraeme Gregory 4027c6750eSGraeme Gregory static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, 4127c6750eSGraeme Gregory int bytes, void *dest) 4227c6750eSGraeme Gregory { 43dc9913a0SLaxman Dewangan return regmap_bulk_read(tps65910->regmap, reg, dest, bytes); 4427c6750eSGraeme Gregory } 4527c6750eSGraeme Gregory 4627c6750eSGraeme Gregory static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg, 4727c6750eSGraeme Gregory int bytes, void *src) 4827c6750eSGraeme Gregory { 49dc9913a0SLaxman Dewangan return regmap_bulk_write(tps65910->regmap, reg, src, bytes); 5027c6750eSGraeme Gregory } 5127c6750eSGraeme Gregory 5227c6750eSGraeme Gregory int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask) 5327c6750eSGraeme Gregory { 54dc9913a0SLaxman Dewangan return regmap_update_bits(tps65910->regmap, reg, mask, mask); 5527c6750eSGraeme Gregory } 5627c6750eSGraeme Gregory EXPORT_SYMBOL_GPL(tps65910_set_bits); 5727c6750eSGraeme Gregory 5827c6750eSGraeme Gregory int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) 5927c6750eSGraeme Gregory { 60dc9913a0SLaxman Dewangan return regmap_update_bits(tps65910->regmap, reg, mask, 0); 6127c6750eSGraeme Gregory } 6227c6750eSGraeme Gregory EXPORT_SYMBOL_GPL(tps65910_clear_bits); 6327c6750eSGraeme Gregory 64dc9913a0SLaxman Dewangan static bool is_volatile_reg(struct device *dev, unsigned int reg) 65dc9913a0SLaxman Dewangan { 66dc9913a0SLaxman Dewangan struct tps65910 *tps65910 = dev_get_drvdata(dev); 67dc9913a0SLaxman Dewangan 68dc9913a0SLaxman Dewangan /* 69dc9913a0SLaxman Dewangan * Caching all regulator registers. 70dc9913a0SLaxman Dewangan * All regualator register address range is same for 71dc9913a0SLaxman Dewangan * TPS65910 and TPS65911 72dc9913a0SLaxman Dewangan */ 73dc9913a0SLaxman Dewangan if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) { 74dc9913a0SLaxman Dewangan /* Check for non-existing register */ 75dc9913a0SLaxman Dewangan if (tps65910_chip_id(tps65910) == TPS65910) 76dc9913a0SLaxman Dewangan if ((reg == TPS65911_VDDCTRL_OP) || 77dc9913a0SLaxman Dewangan (reg == TPS65911_VDDCTRL_SR)) 78dc9913a0SLaxman Dewangan return true; 79dc9913a0SLaxman Dewangan return false; 80dc9913a0SLaxman Dewangan } 81dc9913a0SLaxman Dewangan return true; 82dc9913a0SLaxman Dewangan } 83dc9913a0SLaxman Dewangan 8439ecb037SLaxman Dewangan static const struct regmap_config tps65910_regmap_config = { 85dc9913a0SLaxman Dewangan .reg_bits = 8, 86dc9913a0SLaxman Dewangan .val_bits = 8, 87dc9913a0SLaxman Dewangan .volatile_reg = is_volatile_reg, 88dc9913a0SLaxman Dewangan .max_register = TPS65910_MAX_REGISTER, 89dc9913a0SLaxman Dewangan .num_reg_defaults_raw = TPS65910_MAX_REGISTER, 90dc9913a0SLaxman Dewangan .cache_type = REGCACHE_RBTREE, 91dc9913a0SLaxman Dewangan }; 92dc9913a0SLaxman Dewangan 93*63745d40SMark Brown static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, 94201cf052SLaxman Dewangan struct tps65910_board *pmic_pdata) 95201cf052SLaxman Dewangan { 96201cf052SLaxman Dewangan struct device *dev = NULL; 97201cf052SLaxman Dewangan int ret = 0; 98201cf052SLaxman Dewangan 99201cf052SLaxman Dewangan dev = tps65910->dev; 100201cf052SLaxman Dewangan 101201cf052SLaxman Dewangan if (!pmic_pdata->en_dev_slp) 102201cf052SLaxman Dewangan return 0; 103201cf052SLaxman Dewangan 104201cf052SLaxman Dewangan /* enabling SLEEP device state */ 105201cf052SLaxman Dewangan ret = tps65910_set_bits(tps65910, TPS65910_DEVCTRL, 106201cf052SLaxman Dewangan DEVCTRL_DEV_SLP_MASK); 107201cf052SLaxman Dewangan if (ret < 0) { 108201cf052SLaxman Dewangan dev_err(dev, "set dev_slp failed: %d\n", ret); 109201cf052SLaxman Dewangan goto err_sleep_init; 110201cf052SLaxman Dewangan } 111201cf052SLaxman Dewangan 112201cf052SLaxman Dewangan /* Return if there is no sleep keepon data. */ 113201cf052SLaxman Dewangan if (!pmic_pdata->slp_keepon) 114201cf052SLaxman Dewangan return 0; 115201cf052SLaxman Dewangan 116201cf052SLaxman Dewangan if (pmic_pdata->slp_keepon->therm_keepon) { 117201cf052SLaxman Dewangan ret = tps65910_set_bits(tps65910, TPS65910_SLEEP_KEEP_RES_ON, 118201cf052SLaxman Dewangan SLEEP_KEEP_RES_ON_THERM_KEEPON_MASK); 119201cf052SLaxman Dewangan if (ret < 0) { 120201cf052SLaxman Dewangan dev_err(dev, "set therm_keepon failed: %d\n", ret); 121201cf052SLaxman Dewangan goto disable_dev_slp; 122201cf052SLaxman Dewangan } 123201cf052SLaxman Dewangan } 124201cf052SLaxman Dewangan 125201cf052SLaxman Dewangan if (pmic_pdata->slp_keepon->clkout32k_keepon) { 126201cf052SLaxman Dewangan ret = tps65910_set_bits(tps65910, TPS65910_SLEEP_KEEP_RES_ON, 127201cf052SLaxman Dewangan SLEEP_KEEP_RES_ON_CLKOUT32K_KEEPON_MASK); 128201cf052SLaxman Dewangan if (ret < 0) { 129201cf052SLaxman Dewangan dev_err(dev, "set clkout32k_keepon failed: %d\n", ret); 130201cf052SLaxman Dewangan goto disable_dev_slp; 131201cf052SLaxman Dewangan } 132201cf052SLaxman Dewangan } 133201cf052SLaxman Dewangan 134201cf052SLaxman Dewangan if (pmic_pdata->slp_keepon->i2chs_keepon) { 135201cf052SLaxman Dewangan ret = tps65910_set_bits(tps65910, 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: 146201cf052SLaxman Dewangan tps65910_clear_bits(tps65910, TPS65910_DEVCTRL, DEVCTRL_DEV_SLP_MASK); 147201cf052SLaxman Dewangan 148201cf052SLaxman Dewangan err_sleep_init: 149201cf052SLaxman Dewangan return ret; 150201cf052SLaxman Dewangan } 151201cf052SLaxman Dewangan 152201cf052SLaxman Dewangan 153*63745d40SMark Brown static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, 15427c6750eSGraeme Gregory const struct i2c_device_id *id) 15527c6750eSGraeme Gregory { 15627c6750eSGraeme Gregory struct tps65910 *tps65910; 1572537df72SGraeme Gregory struct tps65910_board *pmic_plat_data; 158e3471bdcSGraeme Gregory struct tps65910_platform_data *init_data; 15927c6750eSGraeme Gregory int ret = 0; 16027c6750eSGraeme Gregory 1612537df72SGraeme Gregory pmic_plat_data = dev_get_platdata(&i2c->dev); 1622537df72SGraeme Gregory if (!pmic_plat_data) 1632537df72SGraeme Gregory return -EINVAL; 1642537df72SGraeme Gregory 165e3471bdcSGraeme Gregory init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL); 166e3471bdcSGraeme Gregory if (init_data == NULL) 167e3471bdcSGraeme Gregory return -ENOMEM; 168e3471bdcSGraeme Gregory 16927c6750eSGraeme Gregory tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL); 170dc7e412dSJesper Juhl if (tps65910 == NULL) { 171dc7e412dSJesper Juhl kfree(init_data); 17227c6750eSGraeme Gregory return -ENOMEM; 173dc7e412dSJesper Juhl } 17427c6750eSGraeme Gregory 17527c6750eSGraeme Gregory i2c_set_clientdata(i2c, tps65910); 17627c6750eSGraeme Gregory tps65910->dev = &i2c->dev; 17727c6750eSGraeme Gregory tps65910->i2c_client = i2c; 17879557056SJorge Eduardo Candelaria tps65910->id = id->driver_data; 17927c6750eSGraeme Gregory tps65910->read = tps65910_i2c_read; 18027c6750eSGraeme Gregory tps65910->write = tps65910_i2c_write; 18127c6750eSGraeme Gregory mutex_init(&tps65910->io_mutex); 18227c6750eSGraeme Gregory 18339ecb037SLaxman Dewangan tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config); 184dc9913a0SLaxman Dewangan if (IS_ERR(tps65910->regmap)) { 185dc9913a0SLaxman Dewangan ret = PTR_ERR(tps65910->regmap); 186dc9913a0SLaxman Dewangan dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret); 187dc9913a0SLaxman Dewangan goto regmap_err; 188dc9913a0SLaxman Dewangan } 189dc9913a0SLaxman Dewangan 19027c6750eSGraeme Gregory ret = mfd_add_devices(tps65910->dev, -1, 19127c6750eSGraeme Gregory tps65910s, ARRAY_SIZE(tps65910s), 19227c6750eSGraeme Gregory NULL, 0); 19327c6750eSGraeme Gregory if (ret < 0) 19427c6750eSGraeme Gregory goto err; 19527c6750eSGraeme Gregory 196b1224cd1SJesper Juhl init_data->irq = pmic_plat_data->irq; 1971773140fSLaxman Dewangan init_data->irq_base = pmic_plat_data->irq_base; 198b1224cd1SJesper Juhl 1992537df72SGraeme Gregory tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base); 2002537df72SGraeme Gregory 2011e351a95SAfzal Mohammed tps65910_irq_init(tps65910, init_data->irq, init_data); 202e3471bdcSGraeme Gregory 203201cf052SLaxman Dewangan tps65910_sleepinit(tps65910, pmic_plat_data); 204201cf052SLaxman Dewangan 205dc7e412dSJesper Juhl kfree(init_data); 20627c6750eSGraeme Gregory return ret; 20727c6750eSGraeme Gregory 20827c6750eSGraeme Gregory err: 209dc9913a0SLaxman Dewangan regmap_exit(tps65910->regmap); 210dc9913a0SLaxman Dewangan regmap_err: 21127c6750eSGraeme Gregory kfree(tps65910); 212dc7e412dSJesper Juhl kfree(init_data); 21327c6750eSGraeme Gregory return ret; 21427c6750eSGraeme Gregory } 21527c6750eSGraeme Gregory 216*63745d40SMark Brown static __devexit int tps65910_i2c_remove(struct i2c_client *i2c) 21727c6750eSGraeme Gregory { 21827c6750eSGraeme Gregory struct tps65910 *tps65910 = i2c_get_clientdata(i2c); 21927c6750eSGraeme Gregory 220ec2328c3SMark Brown tps65910_irq_exit(tps65910); 2211e351a95SAfzal Mohammed mfd_remove_devices(tps65910->dev); 222dc9913a0SLaxman Dewangan regmap_exit(tps65910->regmap); 22327c6750eSGraeme Gregory kfree(tps65910); 22427c6750eSGraeme Gregory 22527c6750eSGraeme Gregory return 0; 22627c6750eSGraeme Gregory } 22727c6750eSGraeme Gregory 22827c6750eSGraeme Gregory static const struct i2c_device_id tps65910_i2c_id[] = { 22979557056SJorge Eduardo Candelaria { "tps65910", TPS65910 }, 23079557056SJorge Eduardo Candelaria { "tps65911", TPS65911 }, 23127c6750eSGraeme Gregory { } 23227c6750eSGraeme Gregory }; 23327c6750eSGraeme Gregory MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id); 23427c6750eSGraeme Gregory 23527c6750eSGraeme Gregory 23627c6750eSGraeme Gregory static struct i2c_driver tps65910_i2c_driver = { 23727c6750eSGraeme Gregory .driver = { 23827c6750eSGraeme Gregory .name = "tps65910", 23927c6750eSGraeme Gregory .owner = THIS_MODULE, 24027c6750eSGraeme Gregory }, 24127c6750eSGraeme Gregory .probe = tps65910_i2c_probe, 242*63745d40SMark Brown .remove = __devexit_p(tps65910_i2c_remove), 24327c6750eSGraeme Gregory .id_table = tps65910_i2c_id, 24427c6750eSGraeme Gregory }; 24527c6750eSGraeme Gregory 24627c6750eSGraeme Gregory static int __init tps65910_i2c_init(void) 24727c6750eSGraeme Gregory { 24827c6750eSGraeme Gregory return i2c_add_driver(&tps65910_i2c_driver); 24927c6750eSGraeme Gregory } 25027c6750eSGraeme Gregory /* init early so consumer devices can complete system boot */ 25127c6750eSGraeme Gregory subsys_initcall(tps65910_i2c_init); 25227c6750eSGraeme Gregory 25327c6750eSGraeme Gregory static void __exit tps65910_i2c_exit(void) 25427c6750eSGraeme Gregory { 25527c6750eSGraeme Gregory i2c_del_driver(&tps65910_i2c_driver); 25627c6750eSGraeme Gregory } 25727c6750eSGraeme Gregory module_exit(tps65910_i2c_exit); 25827c6750eSGraeme Gregory 25927c6750eSGraeme Gregory MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); 26027c6750eSGraeme Gregory MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>"); 26127c6750eSGraeme Gregory MODULE_DESCRIPTION("TPS6591x chip family multi-function driver"); 26227c6750eSGraeme Gregory MODULE_LICENSE("GPL"); 263