blob: 9bca1b1b60cec6f01219035dd297e3d45decef4a [file] [log] [blame]
Keerthy44b4dc62014-02-06 11:20:12 +05301/*
2 * Driver for TPS65218 Integrated power management chipsets
3 *
4 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether expressed or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License version 2 for more details.
14 */
15
16#include <linux/kernel.h>
17#include <linux/device.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/init.h>
21#include <linux/i2c.h>
22#include <linux/slab.h>
23#include <linux/regmap.h>
24#include <linux/err.h>
25#include <linux/of.h>
26#include <linux/of_device.h>
27#include <linux/irq.h>
28#include <linux/interrupt.h>
29#include <linux/mutex.h>
30
31#include <linux/mfd/core.h>
32#include <linux/mfd/tps65218.h>
33
34#define TPS65218_PASSWORD_REGS_UNLOCK 0x7D
35
36/**
Keerthy44b4dc62014-02-06 11:20:12 +053037 * tps65218_reg_write: Write a single tps65218 register.
38 *
39 * @tps65218: Device to write to.
40 * @reg: Register to write to.
41 * @val: Value to write.
42 * @level: Password protected level
43 */
44int tps65218_reg_write(struct tps65218 *tps, unsigned int reg,
45 unsigned int val, unsigned int level)
46{
47 int ret;
48 unsigned int xor_reg_val;
49
50 switch (level) {
51 case TPS65218_PROTECT_NONE:
52 return regmap_write(tps->regmap, reg, val);
53 case TPS65218_PROTECT_L1:
54 xor_reg_val = reg ^ TPS65218_PASSWORD_REGS_UNLOCK;
55 ret = regmap_write(tps->regmap, TPS65218_REG_PASSWORD,
56 xor_reg_val);
57 if (ret < 0)
58 return ret;
59
60 return regmap_write(tps->regmap, reg, val);
61 default:
62 return -EINVAL;
63 }
64}
65EXPORT_SYMBOL_GPL(tps65218_reg_write);
66
67/**
68 * tps65218_update_bits: Modify bits w.r.t mask, val and level.
69 *
70 * @tps65218: Device to write to.
71 * @reg: Register to read-write to.
72 * @mask: Mask.
73 * @val: Value to write.
74 * @level: Password protected level
75 */
76static int tps65218_update_bits(struct tps65218 *tps, unsigned int reg,
77 unsigned int mask, unsigned int val, unsigned int level)
78{
79 int ret;
80 unsigned int data;
81
Keerthy0aced352016-09-19 13:09:02 +053082 ret = regmap_read(tps->regmap, reg, &data);
Keerthy44b4dc62014-02-06 11:20:12 +053083 if (ret) {
84 dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
85 return ret;
86 }
87
88 data &= ~mask;
89 data |= val & mask;
90
91 mutex_lock(&tps->tps_lock);
92 ret = tps65218_reg_write(tps, reg, data, level);
93 if (ret)
94 dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
95 mutex_unlock(&tps->tps_lock);
96
97 return ret;
98}
99
100int tps65218_set_bits(struct tps65218 *tps, unsigned int reg,
101 unsigned int mask, unsigned int val, unsigned int level)
102{
103 return tps65218_update_bits(tps, reg, mask, val, level);
104}
105EXPORT_SYMBOL_GPL(tps65218_set_bits);
106
107int tps65218_clear_bits(struct tps65218 *tps, unsigned int reg,
108 unsigned int mask, unsigned int level)
109{
110 return tps65218_update_bits(tps, reg, mask, 0, level);
111}
112EXPORT_SYMBOL_GPL(tps65218_clear_bits);
113
Felipe Balbi773328d2014-12-26 13:28:20 -0600114static const struct regmap_range tps65218_yes_ranges[] = {
115 regmap_reg_range(TPS65218_REG_INT1, TPS65218_REG_INT2),
116 regmap_reg_range(TPS65218_REG_STATUS, TPS65218_REG_STATUS),
117};
118
119static const struct regmap_access_table tps65218_volatile_table = {
120 .yes_ranges = tps65218_yes_ranges,
121 .n_yes_ranges = ARRAY_SIZE(tps65218_yes_ranges),
122};
123
Krzysztof Kozlowski18bb3992015-01-05 10:01:31 +0100124static const struct regmap_config tps65218_regmap_config = {
Keerthy44b4dc62014-02-06 11:20:12 +0530125 .reg_bits = 8,
126 .val_bits = 8,
127 .cache_type = REGCACHE_RBTREE,
Felipe Balbi773328d2014-12-26 13:28:20 -0600128 .volatile_table = &tps65218_volatile_table,
Keerthy44b4dc62014-02-06 11:20:12 +0530129};
130
131static const struct regmap_irq tps65218_irqs[] = {
132 /* INT1 IRQs */
133 [TPS65218_PRGC_IRQ] = {
134 .mask = TPS65218_INT1_PRGC,
135 },
136 [TPS65218_CC_AQC_IRQ] = {
137 .mask = TPS65218_INT1_CC_AQC,
138 },
139 [TPS65218_HOT_IRQ] = {
140 .mask = TPS65218_INT1_HOT,
141 },
142 [TPS65218_PB_IRQ] = {
143 .mask = TPS65218_INT1_PB,
144 },
145 [TPS65218_AC_IRQ] = {
146 .mask = TPS65218_INT1_AC,
147 },
148 [TPS65218_VPRG_IRQ] = {
149 .mask = TPS65218_INT1_VPRG,
150 },
151 [TPS65218_INVALID1_IRQ] = {
152 },
153 [TPS65218_INVALID2_IRQ] = {
154 },
155 /* INT2 IRQs*/
156 [TPS65218_LS1_I_IRQ] = {
157 .mask = TPS65218_INT2_LS1_I,
158 .reg_offset = 1,
159 },
160 [TPS65218_LS2_I_IRQ] = {
161 .mask = TPS65218_INT2_LS2_I,
162 .reg_offset = 1,
163 },
164 [TPS65218_LS3_I_IRQ] = {
165 .mask = TPS65218_INT2_LS3_I,
166 .reg_offset = 1,
167 },
168 [TPS65218_LS1_F_IRQ] = {
169 .mask = TPS65218_INT2_LS1_F,
170 .reg_offset = 1,
171 },
172 [TPS65218_LS2_F_IRQ] = {
173 .mask = TPS65218_INT2_LS2_F,
174 .reg_offset = 1,
175 },
176 [TPS65218_LS3_F_IRQ] = {
177 .mask = TPS65218_INT2_LS3_F,
178 .reg_offset = 1,
179 },
180 [TPS65218_INVALID3_IRQ] = {
181 },
182 [TPS65218_INVALID4_IRQ] = {
183 },
184};
185
186static struct regmap_irq_chip tps65218_irq_chip = {
187 .name = "tps65218",
188 .irqs = tps65218_irqs,
189 .num_irqs = ARRAY_SIZE(tps65218_irqs),
190
191 .num_regs = 2,
192 .mask_base = TPS65218_REG_INT_MASK1,
Felipe Balbif29ae362014-12-26 13:28:21 -0600193 .status_base = TPS65218_REG_INT1,
Keerthy44b4dc62014-02-06 11:20:12 +0530194};
195
196static const struct of_device_id of_tps65218_match_table[] = {
197 { .compatible = "ti,tps65218", },
Stephen Boyd83205132014-05-23 17:16:52 -0700198 {}
Keerthy44b4dc62014-02-06 11:20:12 +0530199};
Javier Martinez Canillas4895e492015-07-30 18:18:41 +0200200MODULE_DEVICE_TABLE(of, of_tps65218_match_table);
Keerthy44b4dc62014-02-06 11:20:12 +0530201
202static int tps65218_probe(struct i2c_client *client,
203 const struct i2c_device_id *ids)
204{
205 struct tps65218 *tps;
206 const struct of_device_id *match;
207 int ret;
Tero Kristof11fa172016-08-10 17:53:54 +0530208 unsigned int chipid;
Keerthy44b4dc62014-02-06 11:20:12 +0530209
210 match = of_match_device(of_tps65218_match_table, &client->dev);
211 if (!match) {
212 dev_err(&client->dev,
213 "Failed to find matching dt id\n");
214 return -EINVAL;
215 }
216
217 tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
218 if (!tps)
219 return -ENOMEM;
220
221 i2c_set_clientdata(client, tps);
222 tps->dev = &client->dev;
223 tps->irq = client->irq;
224 tps->regmap = devm_regmap_init_i2c(client, &tps65218_regmap_config);
225 if (IS_ERR(tps->regmap)) {
226 ret = PTR_ERR(tps->regmap);
227 dev_err(tps->dev, "Failed to allocate register map: %d\n",
228 ret);
229 return ret;
230 }
231
232 mutex_init(&tps->tps_lock);
233
234 ret = regmap_add_irq_chip(tps->regmap, tps->irq,
235 IRQF_ONESHOT, 0, &tps65218_irq_chip,
236 &tps->irq_data);
237 if (ret < 0)
238 return ret;
239
Keerthy0aced352016-09-19 13:09:02 +0530240 ret = regmap_read(tps->regmap, TPS65218_REG_CHIPID, &chipid);
Tero Kristof11fa172016-08-10 17:53:54 +0530241 if (ret) {
242 dev_err(tps->dev, "Failed to read chipid: %d\n", ret);
243 return ret;
244 }
245
246 tps->rev = chipid & TPS65218_CHIPID_REV_MASK;
247
Keerthy44b4dc62014-02-06 11:20:12 +0530248 ret = of_platform_populate(client->dev.of_node, NULL, NULL,
249 &client->dev);
250 if (ret < 0)
251 goto err_irq;
252
253 return 0;
254
255err_irq:
256 regmap_del_irq_chip(tps->irq, tps->irq_data);
257
258 return ret;
259}
260
261static int tps65218_remove(struct i2c_client *client)
262{
263 struct tps65218 *tps = i2c_get_clientdata(client);
264
265 regmap_del_irq_chip(tps->irq, tps->irq_data);
266
267 return 0;
268}
269
270static const struct i2c_device_id tps65218_id_table[] = {
271 { "tps65218", TPS65218 },
272 { },
273};
274MODULE_DEVICE_TABLE(i2c, tps65218_id_table);
275
276static struct i2c_driver tps65218_driver = {
277 .driver = {
278 .name = "tps65218",
Keerthy44b4dc62014-02-06 11:20:12 +0530279 .of_match_table = of_tps65218_match_table,
280 },
281 .probe = tps65218_probe,
282 .remove = tps65218_remove,
283 .id_table = tps65218_id_table,
284};
285
286module_i2c_driver(tps65218_driver);
287
288MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
289MODULE_DESCRIPTION("TPS65218 chip family multi-function driver");
290MODULE_LICENSE("GPL v2");