4 * Copyright 2011-2012 Texas Instruments Inc.
6 * Author: Graeme Gregory <gg@slimlogic.co.uk>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
15 #include <linux/module.h>
16 #include <linux/moduleparam.h>
17 #include <linux/init.h>
18 #include <linux/slab.h>
19 #include <linux/i2c.h>
20 #include <linux/interrupt.h>
21 #include <linux/irq.h>
22 #include <linux/regmap.h>
23 #include <linux/err.h>
24 #include <linux/mfd/core.h>
25 #include <linux/mfd/palmas.h>
26 #include <linux/of_platform.h>
28 static const struct regmap_config palmas_regmap_config
[PALMAS_NUM_CLIENTS
] = {
32 .max_register
= PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE
,
33 PALMAS_PRIMARY_SECONDARY_PAD3
),
38 .max_register
= PALMAS_BASE_TO_REG(PALMAS_GPADC_BASE
,
39 PALMAS_GPADC_SMPS_VSEL_MONITORING
),
44 .max_register
= PALMAS_BASE_TO_REG(PALMAS_TRIM_GPADC_BASE
,
49 static const struct regmap_irq palmas_irqs
[] = {
51 [PALMAS_CHARG_DET_N_VBUS_OVV_IRQ
] = {
52 .mask
= PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV
,
54 [PALMAS_PWRON_IRQ
] = {
55 .mask
= PALMAS_INT1_STATUS_PWRON
,
57 [PALMAS_LONG_PRESS_KEY_IRQ
] = {
58 .mask
= PALMAS_INT1_STATUS_LONG_PRESS_KEY
,
60 [PALMAS_RPWRON_IRQ
] = {
61 .mask
= PALMAS_INT1_STATUS_RPWRON
,
63 [PALMAS_PWRDOWN_IRQ
] = {
64 .mask
= PALMAS_INT1_STATUS_PWRDOWN
,
66 [PALMAS_HOTDIE_IRQ
] = {
67 .mask
= PALMAS_INT1_STATUS_HOTDIE
,
69 [PALMAS_VSYS_MON_IRQ
] = {
70 .mask
= PALMAS_INT1_STATUS_VSYS_MON
,
72 [PALMAS_VBAT_MON_IRQ
] = {
73 .mask
= PALMAS_INT1_STATUS_VBAT_MON
,
76 [PALMAS_RTC_ALARM_IRQ
] = {
77 .mask
= PALMAS_INT2_STATUS_RTC_ALARM
,
80 [PALMAS_RTC_TIMER_IRQ
] = {
81 .mask
= PALMAS_INT2_STATUS_RTC_TIMER
,
85 .mask
= PALMAS_INT2_STATUS_WDT
,
88 [PALMAS_BATREMOVAL_IRQ
] = {
89 .mask
= PALMAS_INT2_STATUS_BATREMOVAL
,
92 [PALMAS_RESET_IN_IRQ
] = {
93 .mask
= PALMAS_INT2_STATUS_RESET_IN
,
96 [PALMAS_FBI_BB_IRQ
] = {
97 .mask
= PALMAS_INT2_STATUS_FBI_BB
,
100 [PALMAS_SHORT_IRQ
] = {
101 .mask
= PALMAS_INT2_STATUS_SHORT
,
104 [PALMAS_VAC_ACOK_IRQ
] = {
105 .mask
= PALMAS_INT2_STATUS_VAC_ACOK
,
109 [PALMAS_GPADC_AUTO_0_IRQ
] = {
110 .mask
= PALMAS_INT3_STATUS_GPADC_AUTO_0
,
113 [PALMAS_GPADC_AUTO_1_IRQ
] = {
114 .mask
= PALMAS_INT3_STATUS_GPADC_AUTO_1
,
117 [PALMAS_GPADC_EOC_SW_IRQ
] = {
118 .mask
= PALMAS_INT3_STATUS_GPADC_EOC_SW
,
121 [PALMAS_GPADC_EOC_RT_IRQ
] = {
122 .mask
= PALMAS_INT3_STATUS_GPADC_EOC_RT
,
125 [PALMAS_ID_OTG_IRQ
] = {
126 .mask
= PALMAS_INT3_STATUS_ID_OTG
,
130 .mask
= PALMAS_INT3_STATUS_ID
,
133 [PALMAS_VBUS_OTG_IRQ
] = {
134 .mask
= PALMAS_INT3_STATUS_VBUS_OTG
,
137 [PALMAS_VBUS_IRQ
] = {
138 .mask
= PALMAS_INT3_STATUS_VBUS
,
142 [PALMAS_GPIO_0_IRQ
] = {
143 .mask
= PALMAS_INT4_STATUS_GPIO_0
,
146 [PALMAS_GPIO_1_IRQ
] = {
147 .mask
= PALMAS_INT4_STATUS_GPIO_1
,
150 [PALMAS_GPIO_2_IRQ
] = {
151 .mask
= PALMAS_INT4_STATUS_GPIO_2
,
154 [PALMAS_GPIO_3_IRQ
] = {
155 .mask
= PALMAS_INT4_STATUS_GPIO_3
,
158 [PALMAS_GPIO_4_IRQ
] = {
159 .mask
= PALMAS_INT4_STATUS_GPIO_4
,
162 [PALMAS_GPIO_5_IRQ
] = {
163 .mask
= PALMAS_INT4_STATUS_GPIO_5
,
166 [PALMAS_GPIO_6_IRQ
] = {
167 .mask
= PALMAS_INT4_STATUS_GPIO_6
,
170 [PALMAS_GPIO_7_IRQ
] = {
171 .mask
= PALMAS_INT4_STATUS_GPIO_7
,
176 static struct regmap_irq_chip palmas_irq_chip
= {
179 .num_irqs
= ARRAY_SIZE(palmas_irqs
),
183 .status_base
= PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE
,
185 .mask_base
= PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE
,
189 static int palmas_set_pdata_irq_flag(struct i2c_client
*i2c
,
190 struct palmas_platform_data
*pdata
)
192 struct irq_data
*irq_data
= irq_get_irq_data(i2c
->irq
);
194 dev_err(&i2c
->dev
, "Invalid IRQ: %d\n", i2c
->irq
);
198 pdata
->irq_flags
= irqd_get_trigger_type(irq_data
);
199 dev_info(&i2c
->dev
, "Irq flag is 0x%08x\n", pdata
->irq_flags
);
203 static void palmas_dt_to_pdata(struct i2c_client
*i2c
,
204 struct palmas_platform_data
*pdata
)
206 struct device_node
*node
= i2c
->dev
.of_node
;
210 ret
= of_property_read_u32(node
, "ti,mux-pad1", &prop
);
212 pdata
->mux_from_pdata
= 1;
216 ret
= of_property_read_u32(node
, "ti,mux-pad2", &prop
);
218 pdata
->mux_from_pdata
= 1;
222 /* The default for this register is all masked */
223 ret
= of_property_read_u32(node
, "ti,power-ctrl", &prop
);
225 pdata
->power_ctrl
= prop
;
227 pdata
->power_ctrl
= PALMAS_POWER_CTRL_NSLEEP_MASK
|
228 PALMAS_POWER_CTRL_ENABLE1_MASK
|
229 PALMAS_POWER_CTRL_ENABLE2_MASK
;
231 palmas_set_pdata_irq_flag(i2c
, pdata
);
234 static int palmas_i2c_probe(struct i2c_client
*i2c
,
235 const struct i2c_device_id
*id
)
237 struct palmas
*palmas
;
238 struct palmas_platform_data
*pdata
;
239 struct device_node
*node
= i2c
->dev
.of_node
;
241 unsigned int reg
, addr
;
244 pdata
= dev_get_platdata(&i2c
->dev
);
246 if (node
&& !pdata
) {
247 pdata
= devm_kzalloc(&i2c
->dev
, sizeof(*pdata
), GFP_KERNEL
);
252 palmas_dt_to_pdata(i2c
, pdata
);
258 palmas
= devm_kzalloc(&i2c
->dev
, sizeof(struct palmas
), GFP_KERNEL
);
262 i2c_set_clientdata(i2c
, palmas
);
263 palmas
->dev
= &i2c
->dev
;
264 palmas
->id
= id
->driver_data
;
265 palmas
->irq
= i2c
->irq
;
267 for (i
= 0; i
< PALMAS_NUM_CLIENTS
; i
++) {
269 palmas
->i2c_clients
[i
] = i2c
;
271 palmas
->i2c_clients
[i
] =
272 i2c_new_dummy(i2c
->adapter
,
274 if (!palmas
->i2c_clients
[i
]) {
276 "can't attach client %d\n", i
);
280 palmas
->i2c_clients
[i
]->dev
.of_node
= of_node_get(node
);
282 palmas
->regmap
[i
] = devm_regmap_init_i2c(palmas
->i2c_clients
[i
],
283 &palmas_regmap_config
[i
]);
284 if (IS_ERR(palmas
->regmap
[i
])) {
285 ret
= PTR_ERR(palmas
->regmap
[i
]);
287 "Failed to allocate regmap %d, err: %d\n",
293 /* Change interrupt line output polarity */
294 if (pdata
->irq_flags
& IRQ_TYPE_LEVEL_HIGH
)
295 reg
= PALMAS_POLARITY_CTRL_INT_POLARITY
;
298 ret
= palmas_update_bits(palmas
, PALMAS_PU_PD_OD_BASE
,
299 PALMAS_POLARITY_CTRL
, PALMAS_POLARITY_CTRL_INT_POLARITY
,
302 dev_err(palmas
->dev
, "POLARITY_CTRL updat failed: %d\n", ret
);
306 /* Change IRQ into clear on read mode for efficiency */
307 slave
= PALMAS_BASE_TO_SLAVE(PALMAS_INTERRUPT_BASE
);
308 addr
= PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE
, PALMAS_INT_CTRL
);
309 reg
= PALMAS_INT_CTRL_INT_CLEAR
;
311 regmap_write(palmas
->regmap
[slave
], addr
, reg
);
313 ret
= regmap_add_irq_chip(palmas
->regmap
[slave
], palmas
->irq
,
314 IRQF_ONESHOT
| pdata
->irq_flags
, 0, &palmas_irq_chip
,
319 slave
= PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE
);
320 addr
= PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE
,
321 PALMAS_PRIMARY_SECONDARY_PAD1
);
323 if (pdata
->mux_from_pdata
) {
325 ret
= regmap_write(palmas
->regmap
[slave
], addr
, reg
);
329 ret
= regmap_read(palmas
->regmap
[slave
], addr
, ®
);
334 if (!(reg
& PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0
))
335 palmas
->gpio_muxed
|= PALMAS_GPIO_0_MUXED
;
336 if (!(reg
& PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK
))
337 palmas
->gpio_muxed
|= PALMAS_GPIO_1_MUXED
;
338 else if ((reg
& PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK
) ==
339 (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT
))
340 palmas
->led_muxed
|= PALMAS_LED1_MUXED
;
341 else if ((reg
& PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK
) ==
342 (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT
))
343 palmas
->pwm_muxed
|= PALMAS_PWM1_MUXED
;
344 if (!(reg
& PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK
))
345 palmas
->gpio_muxed
|= PALMAS_GPIO_2_MUXED
;
346 else if ((reg
& PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK
) ==
347 (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT
))
348 palmas
->led_muxed
|= PALMAS_LED2_MUXED
;
349 else if ((reg
& PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK
) ==
350 (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT
))
351 palmas
->pwm_muxed
|= PALMAS_PWM2_MUXED
;
352 if (!(reg
& PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3
))
353 palmas
->gpio_muxed
|= PALMAS_GPIO_3_MUXED
;
355 addr
= PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE
,
356 PALMAS_PRIMARY_SECONDARY_PAD2
);
358 if (pdata
->mux_from_pdata
) {
360 ret
= regmap_write(palmas
->regmap
[slave
], addr
, reg
);
364 ret
= regmap_read(palmas
->regmap
[slave
], addr
, ®
);
369 if (!(reg
& PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4
))
370 palmas
->gpio_muxed
|= PALMAS_GPIO_4_MUXED
;
371 if (!(reg
& PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK
))
372 palmas
->gpio_muxed
|= PALMAS_GPIO_5_MUXED
;
373 if (!(reg
& PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6
))
374 palmas
->gpio_muxed
|= PALMAS_GPIO_6_MUXED
;
375 if (!(reg
& PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK
))
376 palmas
->gpio_muxed
|= PALMAS_GPIO_7_MUXED
;
378 dev_info(palmas
->dev
, "Muxing GPIO %x, PWM %x, LED %x\n",
379 palmas
->gpio_muxed
, palmas
->pwm_muxed
,
382 reg
= pdata
->power_ctrl
;
384 slave
= PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE
);
385 addr
= PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE
, PALMAS_POWER_CTRL
);
387 ret
= regmap_write(palmas
->regmap
[slave
], addr
, reg
);
392 * If we are probing with DT do this the DT way and return here
393 * otherwise continue and add devices using mfd helpers.
396 ret
= of_platform_populate(node
, NULL
, NULL
, &i2c
->dev
);
406 regmap_del_irq_chip(palmas
->irq
, palmas
->irq_data
);
411 static int palmas_i2c_remove(struct i2c_client
*i2c
)
413 struct palmas
*palmas
= i2c_get_clientdata(i2c
);
415 mfd_remove_devices(palmas
->dev
);
416 regmap_del_irq_chip(palmas
->irq
, palmas
->irq_data
);
421 static const struct i2c_device_id palmas_i2c_id
[] = {
428 MODULE_DEVICE_TABLE(i2c
, palmas_i2c_id
);
430 static struct of_device_id of_palmas_match_tbl
[] = {
431 { .compatible
= "ti,palmas", },
435 static struct i2c_driver palmas_i2c_driver
= {
438 .of_match_table
= of_palmas_match_tbl
,
439 .owner
= THIS_MODULE
,
441 .probe
= palmas_i2c_probe
,
442 .remove
= palmas_i2c_remove
,
443 .id_table
= palmas_i2c_id
,
446 static int __init
palmas_i2c_init(void)
448 return i2c_add_driver(&palmas_i2c_driver
);
450 /* init early so consumer devices can complete system boot */
451 subsys_initcall(palmas_i2c_init
);
453 static void __exit
palmas_i2c_exit(void)
455 i2c_del_driver(&palmas_i2c_driver
);
457 module_exit(palmas_i2c_exit
);
459 MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
460 MODULE_DESCRIPTION("Palmas chip family multi-function driver");
461 MODULE_LICENSE("GPL");