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