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 28 #include <linux/mfd/core.h> 29 #include <linux/mfd/tps65217.h> 30 31 /** 32 * tps65217_reg_read: Read a single tps65217 register. 33 * 34 * @tps: Device to read from. 35 * @reg: Register to read. 36 * @val: Contians the value 37 */ 38 int tps65217_reg_read(struct tps65217 *tps, unsigned int reg, 39 unsigned int *val) 40 { 41 return regmap_read(tps->regmap, reg, val); 42 } 43 EXPORT_SYMBOL_GPL(tps65217_reg_read); 44 45 /** 46 * tps65217_reg_write: Write a single tps65217 register. 47 * 48 * @tps65217: Device to write to. 49 * @reg: Register to write to. 50 * @val: Value to write. 51 * @level: Password protected level 52 */ 53 int tps65217_reg_write(struct tps65217 *tps, unsigned int reg, 54 unsigned int val, unsigned int level) 55 { 56 int ret; 57 unsigned int xor_reg_val; 58 59 switch (level) { 60 case TPS65217_PROTECT_NONE: 61 return regmap_write(tps->regmap, reg, val); 62 case TPS65217_PROTECT_L1: 63 xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK; 64 ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD, 65 xor_reg_val); 66 if (ret < 0) 67 return ret; 68 69 return regmap_write(tps->regmap, reg, val); 70 case TPS65217_PROTECT_L2: 71 xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK; 72 ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD, 73 xor_reg_val); 74 if (ret < 0) 75 return ret; 76 ret = regmap_write(tps->regmap, reg, val); 77 if (ret < 0) 78 return ret; 79 ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD, 80 xor_reg_val); 81 if (ret < 0) 82 return ret; 83 return regmap_write(tps->regmap, reg, val); 84 default: 85 return -EINVAL; 86 } 87 } 88 EXPORT_SYMBOL_GPL(tps65217_reg_write); 89 90 /** 91 * tps65217_update_bits: Modify bits w.r.t mask, val and level. 92 * 93 * @tps65217: Device to write to. 94 * @reg: Register to read-write to. 95 * @mask: Mask. 96 * @val: Value to write. 97 * @level: Password protected level 98 */ 99 int tps65217_update_bits(struct tps65217 *tps, unsigned int reg, 100 unsigned int mask, unsigned int val, unsigned int level) 101 { 102 int ret; 103 unsigned int data; 104 105 ret = tps65217_reg_read(tps, reg, &data); 106 if (ret) { 107 dev_err(tps->dev, "Read from reg 0x%x failed\n", reg); 108 return ret; 109 } 110 111 data &= ~mask; 112 data |= val & mask; 113 114 ret = tps65217_reg_write(tps, reg, data, level); 115 if (ret) 116 dev_err(tps->dev, "Write for reg 0x%x failed\n", reg); 117 118 return ret; 119 } 120 121 int tps65217_set_bits(struct tps65217 *tps, unsigned int reg, 122 unsigned int mask, unsigned int val, unsigned int level) 123 { 124 return tps65217_update_bits(tps, reg, mask, val, level); 125 } 126 EXPORT_SYMBOL_GPL(tps65217_set_bits); 127 128 int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg, 129 unsigned int mask, unsigned int level) 130 { 131 return tps65217_update_bits(tps, reg, mask, 0, level); 132 } 133 EXPORT_SYMBOL_GPL(tps65217_clear_bits); 134 135 static struct regmap_config tps65217_regmap_config = { 136 .reg_bits = 8, 137 .val_bits = 8, 138 }; 139 140 static int __devinit tps65217_probe(struct i2c_client *client, 141 const struct i2c_device_id *ids) 142 { 143 struct tps65217 *tps; 144 struct tps65217_board *pdata = client->dev.platform_data; 145 int i, ret; 146 unsigned int version; 147 148 tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); 149 if (!tps) 150 return -ENOMEM; 151 152 tps->pdata = pdata; 153 tps->regmap = regmap_init_i2c(client, &tps65217_regmap_config); 154 if (IS_ERR(tps->regmap)) { 155 ret = PTR_ERR(tps->regmap); 156 dev_err(tps->dev, "Failed to allocate register map: %d\n", 157 ret); 158 return ret; 159 } 160 161 i2c_set_clientdata(client, tps); 162 tps->dev = &client->dev; 163 164 ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version); 165 if (ret < 0) { 166 dev_err(tps->dev, "Failed to read revision" 167 " register: %d\n", ret); 168 goto err_regmap; 169 } 170 171 dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n", 172 (version & TPS65217_CHIPID_CHIP_MASK) >> 4, 173 version & TPS65217_CHIPID_REV_MASK); 174 175 for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { 176 struct platform_device *pdev; 177 178 pdev = platform_device_alloc("tps65217-pmic", i); 179 if (!pdev) { 180 dev_err(tps->dev, "Cannot create regulator %d\n", i); 181 continue; 182 } 183 184 pdev->dev.parent = tps->dev; 185 platform_device_add_data(pdev, &pdata->tps65217_init_data[i], 186 sizeof(pdata->tps65217_init_data[i])); 187 tps->regulator_pdev[i] = pdev; 188 189 platform_device_add(pdev); 190 } 191 192 return 0; 193 194 err_regmap: 195 regmap_exit(tps->regmap); 196 197 return ret; 198 } 199 200 static int __devexit tps65217_remove(struct i2c_client *client) 201 { 202 struct tps65217 *tps = i2c_get_clientdata(client); 203 int i; 204 205 for (i = 0; i < TPS65217_NUM_REGULATOR; i++) 206 platform_device_unregister(tps->regulator_pdev[i]); 207 208 regmap_exit(tps->regmap); 209 210 return 0; 211 } 212 213 static const struct i2c_device_id tps65217_id_table[] = { 214 {"tps65217", 0xF0}, 215 {/* end of list */} 216 }; 217 MODULE_DEVICE_TABLE(i2c, tps65217_id_table); 218 219 static struct i2c_driver tps65217_driver = { 220 .driver = { 221 .name = "tps65217", 222 }, 223 .id_table = tps65217_id_table, 224 .probe = tps65217_probe, 225 .remove = __devexit_p(tps65217_remove), 226 }; 227 228 static int __init tps65217_init(void) 229 { 230 return i2c_add_driver(&tps65217_driver); 231 } 232 subsys_initcall(tps65217_init); 233 234 static void __exit tps65217_exit(void) 235 { 236 i2c_del_driver(&tps65217_driver); 237 } 238 module_exit(tps65217_exit); 239 240 MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>"); 241 MODULE_DESCRIPTION("TPS65217 chip family multi-function driver"); 242 MODULE_LICENSE("GPL v2"); 243