1 /* 2 * tps65217.c 3 * 4 * TPS65217 chip family multi-function driver 5 * 6 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation version 2. 11 * 12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 13 * kind, whether express or implied; without even the implied warranty 14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18 #include <linux/kernel.h> 19 #include <linux/device.h> 20 #include <linux/module.h> 21 #include <linux/platform_device.h> 22 #include <linux/init.h> 23 #include <linux/i2c.h> 24 #include <linux/slab.h> 25 #include <linux/regmap.h> 26 #include <linux/err.h> 27 #include <linux/regulator/of_regulator.h> 28 29 #include <linux/mfd/core.h> 30 #include <linux/mfd/tps65217.h> 31 32 /** 33 * tps65217_reg_read: Read a single tps65217 register. 34 * 35 * @tps: Device to read from. 36 * @reg: Register to read. 37 * @val: Contians the value 38 */ 39 int tps65217_reg_read(struct tps65217 *tps, unsigned int reg, 40 unsigned int *val) 41 { 42 return regmap_read(tps->regmap, reg, val); 43 } 44 EXPORT_SYMBOL_GPL(tps65217_reg_read); 45 46 /** 47 * tps65217_reg_write: Write a single tps65217 register. 48 * 49 * @tps65217: Device to write to. 50 * @reg: Register to write to. 51 * @val: Value to write. 52 * @level: Password protected level 53 */ 54 int tps65217_reg_write(struct tps65217 *tps, unsigned int reg, 55 unsigned int val, unsigned int level) 56 { 57 int ret; 58 unsigned int xor_reg_val; 59 60 switch (level) { 61 case TPS65217_PROTECT_NONE: 62 return regmap_write(tps->regmap, reg, val); 63 case TPS65217_PROTECT_L1: 64 xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK; 65 ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD, 66 xor_reg_val); 67 if (ret < 0) 68 return ret; 69 70 return regmap_write(tps->regmap, reg, val); 71 case TPS65217_PROTECT_L2: 72 xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK; 73 ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD, 74 xor_reg_val); 75 if (ret < 0) 76 return ret; 77 ret = regmap_write(tps->regmap, reg, val); 78 if (ret < 0) 79 return ret; 80 ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD, 81 xor_reg_val); 82 if (ret < 0) 83 return ret; 84 return regmap_write(tps->regmap, reg, val); 85 default: 86 return -EINVAL; 87 } 88 } 89 EXPORT_SYMBOL_GPL(tps65217_reg_write); 90 91 /** 92 * tps65217_update_bits: Modify bits w.r.t mask, val and level. 93 * 94 * @tps65217: Device to write to. 95 * @reg: Register to read-write to. 96 * @mask: Mask. 97 * @val: Value to write. 98 * @level: Password protected level 99 */ 100 static int tps65217_update_bits(struct tps65217 *tps, unsigned int reg, 101 unsigned int mask, unsigned int val, unsigned int level) 102 { 103 int ret; 104 unsigned int data; 105 106 ret = tps65217_reg_read(tps, reg, &data); 107 if (ret) { 108 dev_err(tps->dev, "Read from reg 0x%x failed\n", reg); 109 return ret; 110 } 111 112 data &= ~mask; 113 data |= val & mask; 114 115 ret = tps65217_reg_write(tps, reg, data, level); 116 if (ret) 117 dev_err(tps->dev, "Write for reg 0x%x failed\n", reg); 118 119 return ret; 120 } 121 122 int tps65217_set_bits(struct tps65217 *tps, unsigned int reg, 123 unsigned int mask, unsigned int val, unsigned int level) 124 { 125 return tps65217_update_bits(tps, reg, mask, val, level); 126 } 127 EXPORT_SYMBOL_GPL(tps65217_set_bits); 128 129 int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg, 130 unsigned int mask, unsigned int level) 131 { 132 return tps65217_update_bits(tps, reg, mask, 0, level); 133 } 134 EXPORT_SYMBOL_GPL(tps65217_clear_bits); 135 136 #ifdef CONFIG_OF 137 static struct of_regulator_match reg_matches[] = { 138 { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 }, 139 { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 }, 140 { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 }, 141 { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 }, 142 { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 }, 143 { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 }, 144 { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 }, 145 }; 146 147 static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client) 148 { 149 struct device_node *node = client->dev.of_node; 150 struct tps65217_board *pdata; 151 struct device_node *regs; 152 int count = ARRAY_SIZE(reg_matches); 153 int ret, i; 154 155 regs = of_find_node_by_name(node, "regulators"); 156 if (!regs) 157 return NULL; 158 159 ret = of_regulator_match(&client->dev, regs, reg_matches, count); 160 of_node_put(regs); 161 if ((ret < 0) || (ret > count)) 162 return NULL; 163 164 count = ret; 165 pdata = devm_kzalloc(&client->dev, count * sizeof(*pdata), GFP_KERNEL); 166 if (!pdata) 167 return NULL; 168 169 for (i = 0; i < count; i++) { 170 if (!reg_matches[i].init_data || !reg_matches[i].of_node) 171 continue; 172 173 pdata->tps65217_init_data[i] = reg_matches[i].init_data; 174 pdata->of_node[i] = reg_matches[i].of_node; 175 } 176 177 return pdata; 178 } 179 180 static struct of_device_id tps65217_of_match[] = { 181 { .compatible = "ti,tps65217", }, 182 { }, 183 }; 184 #else 185 static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client) 186 { 187 return NULL; 188 } 189 #endif 190 191 static struct regmap_config tps65217_regmap_config = { 192 .reg_bits = 8, 193 .val_bits = 8, 194 }; 195 196 static int __devinit tps65217_probe(struct i2c_client *client, 197 const struct i2c_device_id *ids) 198 { 199 struct tps65217 *tps; 200 struct regulator_init_data *reg_data; 201 struct tps65217_board *pdata = client->dev.platform_data; 202 int i, ret; 203 unsigned int version; 204 205 if (!pdata && client->dev.of_node) 206 pdata = tps65217_parse_dt(client); 207 208 tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); 209 if (!tps) 210 return -ENOMEM; 211 212 tps->pdata = pdata; 213 tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config); 214 if (IS_ERR(tps->regmap)) { 215 ret = PTR_ERR(tps->regmap); 216 dev_err(tps->dev, "Failed to allocate register map: %d\n", 217 ret); 218 return ret; 219 } 220 221 i2c_set_clientdata(client, tps); 222 tps->dev = &client->dev; 223 224 ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version); 225 if (ret < 0) { 226 dev_err(tps->dev, "Failed to read revision register: %d\n", 227 ret); 228 return ret; 229 } 230 231 dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n", 232 (version & TPS65217_CHIPID_CHIP_MASK) >> 4, 233 version & TPS65217_CHIPID_REV_MASK); 234 235 for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { 236 struct platform_device *pdev; 237 238 pdev = platform_device_alloc("tps65217-pmic", i); 239 if (!pdev) { 240 dev_err(tps->dev, "Cannot create regulator %d\n", i); 241 continue; 242 } 243 244 pdev->dev.parent = tps->dev; 245 pdev->dev.of_node = pdata->of_node[i]; 246 reg_data = pdata->tps65217_init_data[i]; 247 platform_device_add_data(pdev, reg_data, sizeof(*reg_data)); 248 tps->regulator_pdev[i] = pdev; 249 250 platform_device_add(pdev); 251 } 252 253 return 0; 254 } 255 256 static int __devexit tps65217_remove(struct i2c_client *client) 257 { 258 struct tps65217 *tps = i2c_get_clientdata(client); 259 int i; 260 261 for (i = 0; i < TPS65217_NUM_REGULATOR; i++) 262 platform_device_unregister(tps->regulator_pdev[i]); 263 264 return 0; 265 } 266 267 static const struct i2c_device_id tps65217_id_table[] = { 268 {"tps65217", 0xF0}, 269 {/* end of list */} 270 }; 271 MODULE_DEVICE_TABLE(i2c, tps65217_id_table); 272 273 static struct i2c_driver tps65217_driver = { 274 .driver = { 275 .name = "tps65217", 276 .owner = THIS_MODULE, 277 .of_match_table = of_match_ptr(tps65217_of_match), 278 }, 279 .id_table = tps65217_id_table, 280 .probe = tps65217_probe, 281 .remove = __devexit_p(tps65217_remove), 282 }; 283 284 static int __init tps65217_init(void) 285 { 286 return i2c_add_driver(&tps65217_driver); 287 } 288 subsys_initcall(tps65217_init); 289 290 static void __exit tps65217_exit(void) 291 { 292 i2c_del_driver(&tps65217_driver); 293 } 294 module_exit(tps65217_exit); 295 296 MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>"); 297 MODULE_DESCRIPTION("TPS65217 chip family multi-function driver"); 298 MODULE_LICENSE("GPL v2"); 299