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 }, 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 .max_register = TPS65217_REG_MAX, 151 }; 152 153 static const struct of_device_id tps65217_of_match[] = { 154 { .compatible = "ti,tps65217", .data = (void *)TPS65217 }, 155 { /* sentinel */ }, 156 }; 157 158 static int tps65217_probe(struct i2c_client *client, 159 const struct i2c_device_id *ids) 160 { 161 struct tps65217 *tps; 162 unsigned int version; 163 unsigned long chip_id = ids->driver_data; 164 const struct of_device_id *match; 165 bool status_off = false; 166 int ret; 167 168 if (client->dev.of_node) { 169 match = of_match_device(tps65217_of_match, &client->dev); 170 if (!match) { 171 dev_err(&client->dev, 172 "Failed to find matching dt id\n"); 173 return -EINVAL; 174 } 175 chip_id = (unsigned long)match->data; 176 status_off = of_property_read_bool(client->dev.of_node, 177 "ti,pmic-shutdown-controller"); 178 } 179 180 if (!chip_id) { 181 dev_err(&client->dev, "id is null.\n"); 182 return -ENODEV; 183 } 184 185 tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); 186 if (!tps) 187 return -ENOMEM; 188 189 i2c_set_clientdata(client, tps); 190 tps->dev = &client->dev; 191 tps->id = chip_id; 192 193 tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config); 194 if (IS_ERR(tps->regmap)) { 195 ret = PTR_ERR(tps->regmap); 196 dev_err(tps->dev, "Failed to allocate register map: %d\n", 197 ret); 198 return ret; 199 } 200 201 ret = mfd_add_devices(tps->dev, -1, tps65217s, 202 ARRAY_SIZE(tps65217s), NULL, 0, NULL); 203 if (ret < 0) { 204 dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret); 205 return ret; 206 } 207 208 ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version); 209 if (ret < 0) { 210 dev_err(tps->dev, "Failed to read revision register: %d\n", 211 ret); 212 return ret; 213 } 214 215 /* Set the PMIC to shutdown on PWR_EN toggle */ 216 if (status_off) { 217 ret = tps65217_set_bits(tps, TPS65217_REG_STATUS, 218 TPS65217_STATUS_OFF, TPS65217_STATUS_OFF, 219 TPS65217_PROTECT_NONE); 220 if (ret) 221 dev_warn(tps->dev, "unable to set the status OFF\n"); 222 } 223 224 dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n", 225 (version & TPS65217_CHIPID_CHIP_MASK) >> 4, 226 version & TPS65217_CHIPID_REV_MASK); 227 228 return 0; 229 } 230 231 static int tps65217_remove(struct i2c_client *client) 232 { 233 struct tps65217 *tps = i2c_get_clientdata(client); 234 235 mfd_remove_devices(tps->dev); 236 237 return 0; 238 } 239 240 static const struct i2c_device_id tps65217_id_table[] = { 241 {"tps65217", TPS65217}, 242 { /* sentinel */ } 243 }; 244 MODULE_DEVICE_TABLE(i2c, tps65217_id_table); 245 246 static struct i2c_driver tps65217_driver = { 247 .driver = { 248 .name = "tps65217", 249 .owner = THIS_MODULE, 250 .of_match_table = tps65217_of_match, 251 }, 252 .id_table = tps65217_id_table, 253 .probe = tps65217_probe, 254 .remove = tps65217_remove, 255 }; 256 257 static int __init tps65217_init(void) 258 { 259 return i2c_add_driver(&tps65217_driver); 260 } 261 subsys_initcall(tps65217_init); 262 263 static void __exit tps65217_exit(void) 264 { 265 i2c_del_driver(&tps65217_driver); 266 } 267 module_exit(tps65217_exit); 268 269 MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>"); 270 MODULE_DESCRIPTION("TPS65217 chip family multi-function driver"); 271 MODULE_LICENSE("GPL v2"); 272