2 * Core driver for ams AS3722 PMICs
4 * Copyright (C) 2013 AMS AG
5 * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
7 * Author: Florian Lobmaier <florian.lobmaier@ams.com>
8 * Author: Laxman Dewangan <ldewangan@nvidia.com>
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.
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.
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
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>
34 #include <linux/regmap.h>
35 #include <linux/slab.h>
37 #define AS3722_DEVICE_ID 0x0C
39 static const struct resource as3722_rtc_resource
[] = {
41 .name
= "as3722-rtc-alarm",
42 .start
= AS3722_IRQ_RTC_ALARM
,
43 .end
= AS3722_IRQ_RTC_ALARM
,
44 .flags
= IORESOURCE_IRQ
,
48 static const struct resource as3722_adc_resource
[] = {
51 .start
= AS3722_IRQ_ADC
,
52 .end
= AS3722_IRQ_ADC
,
53 .flags
= IORESOURCE_IRQ
,
57 static const struct mfd_cell as3722_devs
[] = {
59 .name
= "as3722-pinctrl",
62 .name
= "as3722-regulator",
66 .num_resources
= ARRAY_SIZE(as3722_rtc_resource
),
67 .resources
= as3722_rtc_resource
,
71 .num_resources
= ARRAY_SIZE(as3722_adc_resource
),
72 .resources
= as3722_adc_resource
,
75 .name
= "as3722-power-off",
82 static const struct regmap_irq as3722_irqs
[] = {
85 .mask
= AS3722_INTERRUPT_MASK1_LID
,
88 .mask
= AS3722_INTERRUPT_MASK1_ACOK
,
90 [AS3722_IRQ_ENABLE1
] = {
91 .mask
= AS3722_INTERRUPT_MASK1_ENABLE1
,
93 [AS3722_IRQ_OCCUR_ALARM_SD0
] = {
94 .mask
= AS3722_INTERRUPT_MASK1_OCURR_ALARM_SD0
,
96 [AS3722_IRQ_ONKEY_LONG_PRESS
] = {
97 .mask
= AS3722_INTERRUPT_MASK1_ONKEY_LONG
,
99 [AS3722_IRQ_ONKEY
] = {
100 .mask
= AS3722_INTERRUPT_MASK1_ONKEY
,
102 [AS3722_IRQ_OVTMP
] = {
103 .mask
= AS3722_INTERRUPT_MASK1_OVTMP
,
105 [AS3722_IRQ_LOWBAT
] = {
106 .mask
= AS3722_INTERRUPT_MASK1_LOWBAT
,
110 [AS3722_IRQ_SD0_LV
] = {
111 .mask
= AS3722_INTERRUPT_MASK2_SD0_LV
,
114 [AS3722_IRQ_SD1_LV
] = {
115 .mask
= AS3722_INTERRUPT_MASK2_SD1_LV
,
118 [AS3722_IRQ_SD2_LV
] = {
119 .mask
= AS3722_INTERRUPT_MASK2_SD2345_LV
,
122 [AS3722_IRQ_PWM1_OV_PROT
] = {
123 .mask
= AS3722_INTERRUPT_MASK2_PWM1_OV_PROT
,
126 [AS3722_IRQ_PWM2_OV_PROT
] = {
127 .mask
= AS3722_INTERRUPT_MASK2_PWM2_OV_PROT
,
130 [AS3722_IRQ_ENABLE2
] = {
131 .mask
= AS3722_INTERRUPT_MASK2_ENABLE2
,
134 [AS3722_IRQ_SD6_LV
] = {
135 .mask
= AS3722_INTERRUPT_MASK2_SD6_LV
,
138 [AS3722_IRQ_RTC_REP
] = {
139 .mask
= AS3722_INTERRUPT_MASK2_RTC_REP
,
144 [AS3722_IRQ_RTC_ALARM
] = {
145 .mask
= AS3722_INTERRUPT_MASK3_RTC_ALARM
,
148 [AS3722_IRQ_GPIO1
] = {
149 .mask
= AS3722_INTERRUPT_MASK3_GPIO1
,
152 [AS3722_IRQ_GPIO2
] = {
153 .mask
= AS3722_INTERRUPT_MASK3_GPIO2
,
156 [AS3722_IRQ_GPIO3
] = {
157 .mask
= AS3722_INTERRUPT_MASK3_GPIO3
,
160 [AS3722_IRQ_GPIO4
] = {
161 .mask
= AS3722_INTERRUPT_MASK3_GPIO4
,
164 [AS3722_IRQ_GPIO5
] = {
165 .mask
= AS3722_INTERRUPT_MASK3_GPIO5
,
168 [AS3722_IRQ_WATCHDOG
] = {
169 .mask
= AS3722_INTERRUPT_MASK3_WATCHDOG
,
172 [AS3722_IRQ_ENABLE3
] = {
173 .mask
= AS3722_INTERRUPT_MASK3_ENABLE3
,
178 [AS3722_IRQ_TEMP_SD0_SHUTDOWN
] = {
179 .mask
= AS3722_INTERRUPT_MASK4_TEMP_SD0_SHUTDOWN
,
182 [AS3722_IRQ_TEMP_SD1_SHUTDOWN
] = {
183 .mask
= AS3722_INTERRUPT_MASK4_TEMP_SD1_SHUTDOWN
,
186 [AS3722_IRQ_TEMP_SD2_SHUTDOWN
] = {
187 .mask
= AS3722_INTERRUPT_MASK4_TEMP_SD6_SHUTDOWN
,
190 [AS3722_IRQ_TEMP_SD0_ALARM
] = {
191 .mask
= AS3722_INTERRUPT_MASK4_TEMP_SD0_ALARM
,
194 [AS3722_IRQ_TEMP_SD1_ALARM
] = {
195 .mask
= AS3722_INTERRUPT_MASK4_TEMP_SD1_ALARM
,
198 [AS3722_IRQ_TEMP_SD6_ALARM
] = {
199 .mask
= AS3722_INTERRUPT_MASK4_TEMP_SD6_ALARM
,
202 [AS3722_IRQ_OCCUR_ALARM_SD6
] = {
203 .mask
= AS3722_INTERRUPT_MASK4_OCCUR_ALARM_SD6
,
207 .mask
= AS3722_INTERRUPT_MASK4_ADC
,
212 static const struct regmap_irq_chip as3722_irq_chip
= {
215 .num_irqs
= ARRAY_SIZE(as3722_irqs
),
217 .status_base
= AS3722_INTERRUPT_STATUS1_REG
,
218 .mask_base
= AS3722_INTERRUPT_MASK1_REG
,
221 static int as3722_check_device_id(struct as3722
*as3722
)
226 /* Check that this is actually a AS3722 */
227 ret
= as3722_read(as3722
, AS3722_ASIC_ID1_REG
, &val
);
229 dev_err(as3722
->dev
, "ASIC_ID1 read failed: %d\n", ret
);
233 if (val
!= AS3722_DEVICE_ID
) {
234 dev_err(as3722
->dev
, "Device is not AS3722, ID is 0x%x\n", val
);
238 ret
= as3722_read(as3722
, AS3722_ASIC_ID2_REG
, &val
);
240 dev_err(as3722
->dev
, "ASIC_ID2 read failed: %d\n", ret
);
244 dev_info(as3722
->dev
, "AS3722 with revision 0x%x found\n", val
);
248 static int as3722_configure_pullups(struct as3722
*as3722
)
253 if (as3722
->en_intern_int_pullup
)
254 val
|= AS3722_INT_PULL_UP
;
255 if (as3722
->en_intern_i2c_pullup
)
256 val
|= AS3722_I2C_PULL_UP
;
258 ret
= as3722_update_bits(as3722
, AS3722_IOVOLTAGE_REG
,
259 AS3722_INT_PULL_UP
| AS3722_I2C_PULL_UP
, val
);
261 dev_err(as3722
->dev
, "IOVOLTAGE_REG update failed: %d\n", ret
);
265 static const struct regmap_range as3722_readable_ranges
[] = {
266 regmap_reg_range(AS3722_SD0_VOLTAGE_REG
, AS3722_SD6_VOLTAGE_REG
),
267 regmap_reg_range(AS3722_GPIO0_CONTROL_REG
, AS3722_LDO7_VOLTAGE_REG
),
268 regmap_reg_range(AS3722_LDO9_VOLTAGE_REG
, AS3722_REG_SEQU_MOD3_REG
),
269 regmap_reg_range(AS3722_SD_PHSW_CTRL_REG
, AS3722_PWM_CONTROL_H_REG
),
270 regmap_reg_range(AS3722_WATCHDOG_TIMER_REG
, AS3722_WATCHDOG_TIMER_REG
),
271 regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG
,
272 AS3722_BATTERY_VOLTAGE_MONITOR2_REG
),
273 regmap_reg_range(AS3722_SD_CONTROL_REG
, AS3722_PWM_VCONTROL4_REG
),
274 regmap_reg_range(AS3722_BB_CHARGER_REG
, AS3722_SRAM_REG
),
275 regmap_reg_range(AS3722_RTC_ACCESS_REG
, AS3722_RTC_ACCESS_REG
),
276 regmap_reg_range(AS3722_RTC_STATUS_REG
, AS3722_TEMP_STATUS_REG
),
277 regmap_reg_range(AS3722_ADC0_CONTROL_REG
, AS3722_ADC_CONFIGURATION_REG
),
278 regmap_reg_range(AS3722_ASIC_ID1_REG
, AS3722_ASIC_ID2_REG
),
279 regmap_reg_range(AS3722_LOCK_REG
, AS3722_LOCK_REG
),
280 regmap_reg_range(AS3722_FUSE7_REG
, AS3722_FUSE7_REG
),
283 static const struct regmap_access_table as3722_readable_table
= {
284 .yes_ranges
= as3722_readable_ranges
,
285 .n_yes_ranges
= ARRAY_SIZE(as3722_readable_ranges
),
288 static const struct regmap_range as3722_writable_ranges
[] = {
289 regmap_reg_range(AS3722_SD0_VOLTAGE_REG
, AS3722_SD6_VOLTAGE_REG
),
290 regmap_reg_range(AS3722_GPIO0_CONTROL_REG
, AS3722_LDO7_VOLTAGE_REG
),
291 regmap_reg_range(AS3722_LDO9_VOLTAGE_REG
, AS3722_GPIO_SIGNAL_OUT_REG
),
292 regmap_reg_range(AS3722_REG_SEQU_MOD1_REG
, AS3722_REG_SEQU_MOD3_REG
),
293 regmap_reg_range(AS3722_SD_PHSW_CTRL_REG
, AS3722_PWM_CONTROL_H_REG
),
294 regmap_reg_range(AS3722_WATCHDOG_TIMER_REG
, AS3722_WATCHDOG_TIMER_REG
),
295 regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG
,
296 AS3722_BATTERY_VOLTAGE_MONITOR2_REG
),
297 regmap_reg_range(AS3722_SD_CONTROL_REG
, AS3722_PWM_VCONTROL4_REG
),
298 regmap_reg_range(AS3722_BB_CHARGER_REG
, AS3722_SRAM_REG
),
299 regmap_reg_range(AS3722_INTERRUPT_MASK1_REG
, AS3722_TEMP_STATUS_REG
),
300 regmap_reg_range(AS3722_ADC0_CONTROL_REG
, AS3722_ADC1_CONTROL_REG
),
301 regmap_reg_range(AS3722_ADC1_THRESHOLD_HI_MSB_REG
,
302 AS3722_ADC_CONFIGURATION_REG
),
303 regmap_reg_range(AS3722_LOCK_REG
, AS3722_LOCK_REG
),
306 static const struct regmap_access_table as3722_writable_table
= {
307 .yes_ranges
= as3722_writable_ranges
,
308 .n_yes_ranges
= ARRAY_SIZE(as3722_writable_ranges
),
311 static const struct regmap_range as3722_cacheable_ranges
[] = {
312 regmap_reg_range(AS3722_SD0_VOLTAGE_REG
, AS3722_LDO11_VOLTAGE_REG
),
313 regmap_reg_range(AS3722_SD_CONTROL_REG
, AS3722_LDOCONTROL1_REG
),
316 static const struct regmap_access_table as3722_volatile_table
= {
317 .no_ranges
= as3722_cacheable_ranges
,
318 .n_no_ranges
= ARRAY_SIZE(as3722_cacheable_ranges
),
321 static const struct regmap_config as3722_regmap_config
= {
324 .max_register
= AS3722_MAX_REGISTER
,
325 .cache_type
= REGCACHE_RBTREE
,
326 .rd_table
= &as3722_readable_table
,
327 .wr_table
= &as3722_writable_table
,
328 .volatile_table
= &as3722_volatile_table
,
331 static int as3722_i2c_of_probe(struct i2c_client
*i2c
,
332 struct as3722
*as3722
)
334 struct device_node
*np
= i2c
->dev
.of_node
;
335 struct irq_data
*irq_data
;
338 dev_err(&i2c
->dev
, "Device Tree not found\n");
342 irq_data
= irq_get_irq_data(i2c
->irq
);
344 dev_err(&i2c
->dev
, "Invalid IRQ: %d\n", i2c
->irq
);
348 as3722
->en_intern_int_pullup
= of_property_read_bool(np
,
349 "ams,enable-internal-int-pullup");
350 as3722
->en_intern_i2c_pullup
= of_property_read_bool(np
,
351 "ams,enable-internal-i2c-pullup");
352 as3722
->irq_flags
= irqd_get_trigger_type(irq_data
);
353 dev_dbg(&i2c
->dev
, "IRQ flags are 0x%08lx\n", as3722
->irq_flags
);
357 static int as3722_i2c_probe(struct i2c_client
*i2c
,
358 const struct i2c_device_id
*id
)
360 struct as3722
*as3722
;
361 unsigned long irq_flags
;
364 as3722
= devm_kzalloc(&i2c
->dev
, sizeof(struct as3722
), GFP_KERNEL
);
368 as3722
->dev
= &i2c
->dev
;
369 as3722
->chip_irq
= i2c
->irq
;
370 i2c_set_clientdata(i2c
, as3722
);
372 ret
= as3722_i2c_of_probe(i2c
, as3722
);
376 as3722
->regmap
= devm_regmap_init_i2c(i2c
, &as3722_regmap_config
);
377 if (IS_ERR(as3722
->regmap
)) {
378 ret
= PTR_ERR(as3722
->regmap
);
379 dev_err(&i2c
->dev
, "regmap init failed: %d\n", ret
);
383 ret
= as3722_check_device_id(as3722
);
387 irq_flags
= as3722
->irq_flags
| IRQF_ONESHOT
;
388 ret
= regmap_add_irq_chip(as3722
->regmap
, as3722
->chip_irq
,
389 irq_flags
, -1, &as3722_irq_chip
,
392 dev_err(as3722
->dev
, "Failed to add regmap irq: %d\n", ret
);
396 ret
= as3722_configure_pullups(as3722
);
400 ret
= mfd_add_devices(&i2c
->dev
, -1, as3722_devs
,
401 ARRAY_SIZE(as3722_devs
), NULL
, 0,
402 regmap_irq_get_domain(as3722
->irq_data
));
404 dev_err(as3722
->dev
, "Failed to add MFD devices: %d\n", ret
);
408 dev_dbg(as3722
->dev
, "AS3722 core driver initialized successfully\n");
412 regmap_del_irq_chip(as3722
->chip_irq
, as3722
->irq_data
);
416 static int as3722_i2c_remove(struct i2c_client
*i2c
)
418 struct as3722
*as3722
= i2c_get_clientdata(i2c
);
420 mfd_remove_devices(as3722
->dev
);
421 regmap_del_irq_chip(as3722
->chip_irq
, as3722
->irq_data
);
425 static const struct of_device_id as3722_of_match
[] = {
426 { .compatible
= "ams,as3722", },
429 MODULE_DEVICE_TABLE(of
, as3722_of_match
);
431 static const struct i2c_device_id as3722_i2c_id
[] = {
435 MODULE_DEVICE_TABLE(i2c
, as3722_i2c_id
);
437 static struct i2c_driver as3722_i2c_driver
= {
440 .of_match_table
= as3722_of_match
,
442 .probe
= as3722_i2c_probe
,
443 .remove
= as3722_i2c_remove
,
444 .id_table
= as3722_i2c_id
,
447 module_i2c_driver(as3722_i2c_driver
);
449 MODULE_DESCRIPTION("I2C support for AS3722 PMICs");
450 MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>");
451 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
452 MODULE_LICENSE("GPL");