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