xref: /linux/drivers/mfd/as3722.c (revision c4ee0af3fa0dc65f690fc908f02b8355f9576ea0)
1 /*
2  * Core driver for ams AS3722 PMICs
3  *
4  * Copyright (C) 2013 AMS AG
5  * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
6  *
7  * Author: Florian Lobmaier <florian.lobmaier@ams.com>
8  * Author: Laxman Dewangan <ldewangan@nvidia.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23  */
24 
25 #include <linux/err.h>
26 #include <linux/i2c.h>
27 #include <linux/interrupt.h>
28 #include <linux/irq.h>
29 #include <linux/kernel.h>
30 #include <linux/module.h>
31 #include <linux/mfd/core.h>
32 #include <linux/mfd/as3722.h>
33 #include <linux/of.h>
34 #include <linux/regmap.h>
35 #include <linux/slab.h>
36 
37 #define AS3722_DEVICE_ID	0x0C
38 
39 static const struct resource as3722_rtc_resource[] = {
40 	{
41 		.name = "as3722-rtc-alarm",
42 		.start = AS3722_IRQ_RTC_ALARM,
43 		.end = AS3722_IRQ_RTC_ALARM,
44 		.flags = IORESOURCE_IRQ,
45 	},
46 };
47 
48 static const struct resource as3722_adc_resource[] = {
49 	{
50 		.name = "as3722-adc",
51 		.start = AS3722_IRQ_ADC,
52 		.end = AS3722_IRQ_ADC,
53 		.flags = IORESOURCE_IRQ,
54 	},
55 };
56 
57 static struct mfd_cell as3722_devs[] = {
58 	{
59 		.name = "as3722-pinctrl",
60 	},
61 	{
62 		.name = "as3722-regulator",
63 	},
64 	{
65 		.name = "as3722-rtc",
66 		.num_resources = ARRAY_SIZE(as3722_rtc_resource),
67 		.resources = as3722_rtc_resource,
68 	},
69 	{
70 		.name = "as3722-adc",
71 		.num_resources = ARRAY_SIZE(as3722_adc_resource),
72 		.resources = as3722_adc_resource,
73 	},
74 	{
75 		.name = "as3722-power-off",
76 	},
77 };
78 
79 static const struct regmap_irq as3722_irqs[] = {
80 	/* INT1 IRQs */
81 	[AS3722_IRQ_LID] = {
82 		.mask = AS3722_INTERRUPT_MASK1_LID,
83 	},
84 	[AS3722_IRQ_ACOK] = {
85 		.mask = AS3722_INTERRUPT_MASK1_ACOK,
86 	},
87 	[AS3722_IRQ_ENABLE1] = {
88 		.mask = AS3722_INTERRUPT_MASK1_ENABLE1,
89 	},
90 	[AS3722_IRQ_OCCUR_ALARM_SD0] = {
91 		.mask = AS3722_INTERRUPT_MASK1_OCURR_ALARM_SD0,
92 	},
93 	[AS3722_IRQ_ONKEY_LONG_PRESS] = {
94 		.mask = AS3722_INTERRUPT_MASK1_ONKEY_LONG,
95 	},
96 	[AS3722_IRQ_ONKEY] = {
97 		.mask = AS3722_INTERRUPT_MASK1_ONKEY,
98 	},
99 	[AS3722_IRQ_OVTMP] = {
100 		.mask = AS3722_INTERRUPT_MASK1_OVTMP,
101 	},
102 	[AS3722_IRQ_LOWBAT] = {
103 		.mask = AS3722_INTERRUPT_MASK1_LOWBAT,
104 	},
105 
106 	/* INT2 IRQs */
107 	[AS3722_IRQ_SD0_LV] = {
108 		.mask = AS3722_INTERRUPT_MASK2_SD0_LV,
109 		.reg_offset = 1,
110 	},
111 	[AS3722_IRQ_SD1_LV] = {
112 		.mask = AS3722_INTERRUPT_MASK2_SD1_LV,
113 		.reg_offset = 1,
114 	},
115 	[AS3722_IRQ_SD2_LV] = {
116 		.mask = AS3722_INTERRUPT_MASK2_SD2345_LV,
117 		.reg_offset = 1,
118 	},
119 	[AS3722_IRQ_PWM1_OV_PROT] = {
120 		.mask = AS3722_INTERRUPT_MASK2_PWM1_OV_PROT,
121 		.reg_offset = 1,
122 	},
123 	[AS3722_IRQ_PWM2_OV_PROT] = {
124 		.mask = AS3722_INTERRUPT_MASK2_PWM2_OV_PROT,
125 		.reg_offset = 1,
126 	},
127 	[AS3722_IRQ_ENABLE2] = {
128 		.mask = AS3722_INTERRUPT_MASK2_ENABLE2,
129 		.reg_offset = 1,
130 	},
131 	[AS3722_IRQ_SD6_LV] = {
132 		.mask = AS3722_INTERRUPT_MASK2_SD6_LV,
133 		.reg_offset = 1,
134 	},
135 	[AS3722_IRQ_RTC_REP] = {
136 		.mask = AS3722_INTERRUPT_MASK2_RTC_REP,
137 		.reg_offset = 1,
138 	},
139 
140 	/* INT3 IRQs */
141 	[AS3722_IRQ_RTC_ALARM] = {
142 		.mask = AS3722_INTERRUPT_MASK3_RTC_ALARM,
143 		.reg_offset = 2,
144 	},
145 	[AS3722_IRQ_GPIO1] = {
146 		.mask = AS3722_INTERRUPT_MASK3_GPIO1,
147 		.reg_offset = 2,
148 	},
149 	[AS3722_IRQ_GPIO2] = {
150 		.mask = AS3722_INTERRUPT_MASK3_GPIO2,
151 		.reg_offset = 2,
152 	},
153 	[AS3722_IRQ_GPIO3] = {
154 		.mask = AS3722_INTERRUPT_MASK3_GPIO3,
155 		.reg_offset = 2,
156 	},
157 	[AS3722_IRQ_GPIO4] = {
158 		.mask = AS3722_INTERRUPT_MASK3_GPIO4,
159 		.reg_offset = 2,
160 	},
161 	[AS3722_IRQ_GPIO5] = {
162 		.mask = AS3722_INTERRUPT_MASK3_GPIO5,
163 		.reg_offset = 2,
164 	},
165 	[AS3722_IRQ_WATCHDOG] = {
166 		.mask = AS3722_INTERRUPT_MASK3_WATCHDOG,
167 		.reg_offset = 2,
168 	},
169 	[AS3722_IRQ_ENABLE3] = {
170 		.mask = AS3722_INTERRUPT_MASK3_ENABLE3,
171 		.reg_offset = 2,
172 	},
173 
174 	/* INT4 IRQs */
175 	[AS3722_IRQ_TEMP_SD0_SHUTDOWN] = {
176 		.mask = AS3722_INTERRUPT_MASK4_TEMP_SD0_SHUTDOWN,
177 		.reg_offset = 3,
178 	},
179 	[AS3722_IRQ_TEMP_SD1_SHUTDOWN] = {
180 		.mask = AS3722_INTERRUPT_MASK4_TEMP_SD1_SHUTDOWN,
181 		.reg_offset = 3,
182 	},
183 	[AS3722_IRQ_TEMP_SD2_SHUTDOWN] = {
184 		.mask = AS3722_INTERRUPT_MASK4_TEMP_SD6_SHUTDOWN,
185 		.reg_offset = 3,
186 	},
187 	[AS3722_IRQ_TEMP_SD0_ALARM] = {
188 		.mask = AS3722_INTERRUPT_MASK4_TEMP_SD0_ALARM,
189 		.reg_offset = 3,
190 	},
191 	[AS3722_IRQ_TEMP_SD1_ALARM] = {
192 		.mask = AS3722_INTERRUPT_MASK4_TEMP_SD1_ALARM,
193 		.reg_offset = 3,
194 	},
195 	[AS3722_IRQ_TEMP_SD6_ALARM] = {
196 		.mask = AS3722_INTERRUPT_MASK4_TEMP_SD6_ALARM,
197 		.reg_offset = 3,
198 	},
199 	[AS3722_IRQ_OCCUR_ALARM_SD6] = {
200 		.mask = AS3722_INTERRUPT_MASK4_OCCUR_ALARM_SD6,
201 		.reg_offset = 3,
202 	},
203 	[AS3722_IRQ_ADC] = {
204 		.mask = AS3722_INTERRUPT_MASK4_ADC,
205 		.reg_offset = 3,
206 	},
207 };
208 
209 static const struct regmap_irq_chip as3722_irq_chip = {
210 	.name = "as3722",
211 	.irqs = as3722_irqs,
212 	.num_irqs = ARRAY_SIZE(as3722_irqs),
213 	.num_regs = 4,
214 	.status_base = AS3722_INTERRUPT_STATUS1_REG,
215 	.mask_base = AS3722_INTERRUPT_MASK1_REG,
216 };
217 
218 static int as3722_check_device_id(struct as3722 *as3722)
219 {
220 	u32 val;
221 	int ret;
222 
223 	/* Check that this is actually a AS3722 */
224 	ret = as3722_read(as3722, AS3722_ASIC_ID1_REG, &val);
225 	if (ret < 0) {
226 		dev_err(as3722->dev, "ASIC_ID1 read failed: %d\n", ret);
227 		return ret;
228 	}
229 
230 	if (val != AS3722_DEVICE_ID) {
231 		dev_err(as3722->dev, "Device is not AS3722, ID is 0x%x\n", val);
232 		return -ENODEV;
233 	}
234 
235 	ret = as3722_read(as3722, AS3722_ASIC_ID2_REG, &val);
236 	if (ret < 0) {
237 		dev_err(as3722->dev, "ASIC_ID2 read failed: %d\n", ret);
238 		return ret;
239 	}
240 
241 	dev_info(as3722->dev, "AS3722 with revision 0x%x found\n", val);
242 	return 0;
243 }
244 
245 static int as3722_configure_pullups(struct as3722 *as3722)
246 {
247 	int ret;
248 	u32 val = 0;
249 
250 	if (as3722->en_intern_int_pullup)
251 		val |= AS3722_INT_PULL_UP;
252 	if (as3722->en_intern_i2c_pullup)
253 		val |= AS3722_I2C_PULL_UP;
254 
255 	ret = as3722_update_bits(as3722, AS3722_IOVOLTAGE_REG,
256 			AS3722_INT_PULL_UP | AS3722_I2C_PULL_UP, val);
257 	if (ret < 0)
258 		dev_err(as3722->dev, "IOVOLTAGE_REG update failed: %d\n", ret);
259 	return ret;
260 }
261 
262 static const struct regmap_range as3722_readable_ranges[] = {
263 	regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_SD6_VOLTAGE_REG),
264 	regmap_reg_range(AS3722_GPIO0_CONTROL_REG, AS3722_LDO7_VOLTAGE_REG),
265 	regmap_reg_range(AS3722_LDO9_VOLTAGE_REG, AS3722_REG_SEQU_MOD3_REG),
266 	regmap_reg_range(AS3722_SD_PHSW_CTRL_REG, AS3722_PWM_CONTROL_H_REG),
267 	regmap_reg_range(AS3722_WATCHDOG_TIMER_REG, AS3722_WATCHDOG_TIMER_REG),
268 	regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG,
269 					AS3722_BATTERY_VOLTAGE_MONITOR2_REG),
270 	regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_PWM_VCONTROL4_REG),
271 	regmap_reg_range(AS3722_BB_CHARGER_REG, AS3722_SRAM_REG),
272 	regmap_reg_range(AS3722_RTC_ACCESS_REG, AS3722_RTC_ACCESS_REG),
273 	regmap_reg_range(AS3722_RTC_STATUS_REG, AS3722_TEMP_STATUS_REG),
274 	regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC_CONFIGURATION_REG),
275 	regmap_reg_range(AS3722_ASIC_ID1_REG, AS3722_ASIC_ID2_REG),
276 	regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG),
277 };
278 
279 static const struct regmap_access_table as3722_readable_table = {
280 	.yes_ranges = as3722_readable_ranges,
281 	.n_yes_ranges = ARRAY_SIZE(as3722_readable_ranges),
282 };
283 
284 static const struct regmap_range as3722_writable_ranges[] = {
285 	regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_SD6_VOLTAGE_REG),
286 	regmap_reg_range(AS3722_GPIO0_CONTROL_REG, AS3722_LDO7_VOLTAGE_REG),
287 	regmap_reg_range(AS3722_LDO9_VOLTAGE_REG, AS3722_GPIO_SIGNAL_OUT_REG),
288 	regmap_reg_range(AS3722_REG_SEQU_MOD1_REG, AS3722_REG_SEQU_MOD3_REG),
289 	regmap_reg_range(AS3722_SD_PHSW_CTRL_REG, AS3722_PWM_CONTROL_H_REG),
290 	regmap_reg_range(AS3722_WATCHDOG_TIMER_REG, AS3722_WATCHDOG_TIMER_REG),
291 	regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG,
292 					AS3722_BATTERY_VOLTAGE_MONITOR2_REG),
293 	regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_PWM_VCONTROL4_REG),
294 	regmap_reg_range(AS3722_BB_CHARGER_REG, AS3722_SRAM_REG),
295 	regmap_reg_range(AS3722_INTERRUPT_MASK1_REG, AS3722_TEMP_STATUS_REG),
296 	regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC1_CONTROL_REG),
297 	regmap_reg_range(AS3722_ADC1_THRESHOLD_HI_MSB_REG,
298 					AS3722_ADC_CONFIGURATION_REG),
299 	regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG),
300 };
301 
302 static const struct regmap_access_table as3722_writable_table = {
303 	.yes_ranges = as3722_writable_ranges,
304 	.n_yes_ranges = ARRAY_SIZE(as3722_writable_ranges),
305 };
306 
307 static const struct regmap_range as3722_cacheable_ranges[] = {
308 	regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_LDO11_VOLTAGE_REG),
309 	regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_LDOCONTROL1_REG),
310 };
311 
312 static const struct regmap_access_table as3722_volatile_table = {
313 	.no_ranges = as3722_cacheable_ranges,
314 	.n_no_ranges = ARRAY_SIZE(as3722_cacheable_ranges),
315 };
316 
317 static const struct regmap_config as3722_regmap_config = {
318 	.reg_bits = 8,
319 	.val_bits = 8,
320 	.max_register = AS3722_MAX_REGISTER,
321 	.cache_type = REGCACHE_RBTREE,
322 	.rd_table = &as3722_readable_table,
323 	.wr_table = &as3722_writable_table,
324 	.volatile_table = &as3722_volatile_table,
325 };
326 
327 static int as3722_i2c_of_probe(struct i2c_client *i2c,
328 			struct as3722 *as3722)
329 {
330 	struct device_node *np = i2c->dev.of_node;
331 	struct irq_data *irq_data;
332 
333 	if (!np) {
334 		dev_err(&i2c->dev, "Device Tree not found\n");
335 		return -EINVAL;
336 	}
337 
338 	irq_data = irq_get_irq_data(i2c->irq);
339 	if (!irq_data) {
340 		dev_err(&i2c->dev, "Invalid IRQ: %d\n", i2c->irq);
341 		return -EINVAL;
342 	}
343 
344 	as3722->en_intern_int_pullup = of_property_read_bool(np,
345 					"ams,enable-internal-int-pullup");
346 	as3722->en_intern_i2c_pullup = of_property_read_bool(np,
347 					"ams,enable-internal-i2c-pullup");
348 	as3722->irq_flags = irqd_get_trigger_type(irq_data);
349 	dev_dbg(&i2c->dev, "IRQ flags are 0x%08lx\n", as3722->irq_flags);
350 	return 0;
351 }
352 
353 static int as3722_i2c_probe(struct i2c_client *i2c,
354 			const struct i2c_device_id *id)
355 {
356 	struct as3722 *as3722;
357 	unsigned long irq_flags;
358 	int ret;
359 
360 	as3722 = devm_kzalloc(&i2c->dev, sizeof(struct as3722), GFP_KERNEL);
361 	if (!as3722)
362 		return -ENOMEM;
363 
364 	as3722->dev = &i2c->dev;
365 	as3722->chip_irq = i2c->irq;
366 	i2c_set_clientdata(i2c, as3722);
367 
368 	ret = as3722_i2c_of_probe(i2c, as3722);
369 	if (ret < 0)
370 		return ret;
371 
372 	as3722->regmap = devm_regmap_init_i2c(i2c, &as3722_regmap_config);
373 	if (IS_ERR(as3722->regmap)) {
374 		ret = PTR_ERR(as3722->regmap);
375 		dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
376 		return ret;
377 	}
378 
379 	ret = as3722_check_device_id(as3722);
380 	if (ret < 0)
381 		return ret;
382 
383 	irq_flags = as3722->irq_flags | IRQF_ONESHOT;
384 	ret = regmap_add_irq_chip(as3722->regmap, as3722->chip_irq,
385 			irq_flags, -1, &as3722_irq_chip,
386 			&as3722->irq_data);
387 	if (ret < 0) {
388 		dev_err(as3722->dev, "Failed to add regmap irq: %d\n", ret);
389 		return ret;
390 	}
391 
392 	ret = as3722_configure_pullups(as3722);
393 	if (ret < 0)
394 		goto scrub;
395 
396 	ret = mfd_add_devices(&i2c->dev, -1, as3722_devs,
397 			ARRAY_SIZE(as3722_devs), NULL, 0,
398 			regmap_irq_get_domain(as3722->irq_data));
399 	if (ret) {
400 		dev_err(as3722->dev, "Failed to add MFD devices: %d\n", ret);
401 		goto scrub;
402 	}
403 
404 	dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n");
405 	return 0;
406 
407 scrub:
408 	regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data);
409 	return ret;
410 }
411 
412 static int as3722_i2c_remove(struct i2c_client *i2c)
413 {
414 	struct as3722 *as3722 = i2c_get_clientdata(i2c);
415 
416 	mfd_remove_devices(as3722->dev);
417 	regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data);
418 	return 0;
419 }
420 
421 static const struct of_device_id as3722_of_match[] = {
422 	{ .compatible = "ams,as3722", },
423 	{},
424 };
425 MODULE_DEVICE_TABLE(of, as3722_of_match);
426 
427 static const struct i2c_device_id as3722_i2c_id[] = {
428 	{ "as3722", 0 },
429 	{},
430 };
431 MODULE_DEVICE_TABLE(i2c, as3722_i2c_id);
432 
433 static struct i2c_driver as3722_i2c_driver = {
434 	.driver = {
435 		.name = "as3722",
436 		.owner = THIS_MODULE,
437 		.of_match_table = as3722_of_match,
438 	},
439 	.probe = as3722_i2c_probe,
440 	.remove = as3722_i2c_remove,
441 	.id_table = as3722_i2c_id,
442 };
443 
444 module_i2c_driver(as3722_i2c_driver);
445 
446 MODULE_DESCRIPTION("I2C support for AS3722 PMICs");
447 MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>");
448 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
449 MODULE_LICENSE("GPL");
450