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