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 MODULE_DEVICE_TABLE(of, tps65217_of_match); 160 161 static int tps65217_probe(struct i2c_client *client, 162 const struct i2c_device_id *ids) 163 { 164 struct tps65217 *tps; 165 unsigned int version; 166 unsigned long chip_id = ids->driver_data; 167 const struct of_device_id *match; 168 bool status_off = false; 169 int ret; 170 171 if (client->dev.of_node) { 172 match = of_match_device(tps65217_of_match, &client->dev); 173 if (!match) { 174 dev_err(&client->dev, 175 "Failed to find matching dt id\n"); 176 return -EINVAL; 177 } 178 chip_id = (unsigned long)match->data; 179 status_off = of_property_read_bool(client->dev.of_node, 180 "ti,pmic-shutdown-controller"); 181 } 182 183 if (!chip_id) { 184 dev_err(&client->dev, "id is null.\n"); 185 return -ENODEV; 186 } 187 188 tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); 189 if (!tps) 190 return -ENOMEM; 191 192 i2c_set_clientdata(client, tps); 193 tps->dev = &client->dev; 194 tps->id = chip_id; 195 196 tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config); 197 if (IS_ERR(tps->regmap)) { 198 ret = PTR_ERR(tps->regmap); 199 dev_err(tps->dev, "Failed to allocate register map: %d\n", 200 ret); 201 return ret; 202 } 203 204 ret = mfd_add_devices(tps->dev, -1, tps65217s, 205 ARRAY_SIZE(tps65217s), NULL, 0, NULL); 206 if (ret < 0) { 207 dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret); 208 return ret; 209 } 210 211 ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version); 212 if (ret < 0) { 213 dev_err(tps->dev, "Failed to read revision register: %d\n", 214 ret); 215 return ret; 216 } 217 218 /* Set the PMIC to shutdown on PWR_EN toggle */ 219 if (status_off) { 220 ret = tps65217_set_bits(tps, TPS65217_REG_STATUS, 221 TPS65217_STATUS_OFF, TPS65217_STATUS_OFF, 222 TPS65217_PROTECT_NONE); 223 if (ret) 224 dev_warn(tps->dev, "unable to set the status OFF\n"); 225 } 226 227 dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n", 228 (version & TPS65217_CHIPID_CHIP_MASK) >> 4, 229 version & TPS65217_CHIPID_REV_MASK); 230 231 return 0; 232 } 233 234 static int tps65217_remove(struct i2c_client *client) 235 { 236 struct tps65217 *tps = i2c_get_clientdata(client); 237 238 mfd_remove_devices(tps->dev); 239 240 return 0; 241 } 242 243 static const struct i2c_device_id tps65217_id_table[] = { 244 {"tps65217", TPS65217}, 245 { /* sentinel */ } 246 }; 247 MODULE_DEVICE_TABLE(i2c, tps65217_id_table); 248 249 static struct i2c_driver tps65217_driver = { 250 .driver = { 251 .name = "tps65217", 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