diff options
Diffstat (limited to 'drivers/mfd/sec-core.c')
-rw-r--r-- | drivers/mfd/sec-core.c | 176 |
1 files changed, 156 insertions, 20 deletions
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 1d158d5ba8b8..281a82747275 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c | |||
@@ -26,12 +26,14 @@ | |||
26 | #include <linux/mfd/samsung/core.h> | 26 | #include <linux/mfd/samsung/core.h> |
27 | #include <linux/mfd/samsung/irq.h> | 27 | #include <linux/mfd/samsung/irq.h> |
28 | #include <linux/mfd/samsung/rtc.h> | 28 | #include <linux/mfd/samsung/rtc.h> |
29 | #include <linux/mfd/samsung/s2mpa01.h> | ||
29 | #include <linux/mfd/samsung/s2mps11.h> | 30 | #include <linux/mfd/samsung/s2mps11.h> |
31 | #include <linux/mfd/samsung/s2mps14.h> | ||
30 | #include <linux/mfd/samsung/s5m8763.h> | 32 | #include <linux/mfd/samsung/s5m8763.h> |
31 | #include <linux/mfd/samsung/s5m8767.h> | 33 | #include <linux/mfd/samsung/s5m8767.h> |
32 | #include <linux/regmap.h> | 34 | #include <linux/regmap.h> |
33 | 35 | ||
34 | static struct mfd_cell s5m8751_devs[] = { | 36 | static const struct mfd_cell s5m8751_devs[] = { |
35 | { | 37 | { |
36 | .name = "s5m8751-pmic", | 38 | .name = "s5m8751-pmic", |
37 | }, { | 39 | }, { |
@@ -41,7 +43,7 @@ static struct mfd_cell s5m8751_devs[] = { | |||
41 | }, | 43 | }, |
42 | }; | 44 | }; |
43 | 45 | ||
44 | static struct mfd_cell s5m8763_devs[] = { | 46 | static const struct mfd_cell s5m8763_devs[] = { |
45 | { | 47 | { |
46 | .name = "s5m8763-pmic", | 48 | .name = "s5m8763-pmic", |
47 | }, { | 49 | }, { |
@@ -51,15 +53,17 @@ static struct mfd_cell s5m8763_devs[] = { | |||
51 | }, | 53 | }, |
52 | }; | 54 | }; |
53 | 55 | ||
54 | static struct mfd_cell s5m8767_devs[] = { | 56 | static const struct mfd_cell s5m8767_devs[] = { |
55 | { | 57 | { |
56 | .name = "s5m8767-pmic", | 58 | .name = "s5m8767-pmic", |
57 | }, { | 59 | }, { |
58 | .name = "s5m-rtc", | 60 | .name = "s5m-rtc", |
59 | }, | 61 | }, { |
62 | .name = "s5m8767-clk", | ||
63 | } | ||
60 | }; | 64 | }; |
61 | 65 | ||
62 | static struct mfd_cell s2mps11_devs[] = { | 66 | static const struct mfd_cell s2mps11_devs[] = { |
63 | { | 67 | { |
64 | .name = "s2mps11-pmic", | 68 | .name = "s2mps11-pmic", |
65 | }, { | 69 | }, { |
@@ -67,18 +71,53 @@ static struct mfd_cell s2mps11_devs[] = { | |||
67 | } | 71 | } |
68 | }; | 72 | }; |
69 | 73 | ||
74 | static const struct mfd_cell s2mps14_devs[] = { | ||
75 | { | ||
76 | .name = "s2mps14-pmic", | ||
77 | }, { | ||
78 | .name = "s2mps14-rtc", | ||
79 | }, { | ||
80 | .name = "s2mps14-clk", | ||
81 | } | ||
82 | }; | ||
83 | |||
84 | static const struct mfd_cell s2mpa01_devs[] = { | ||
85 | { | ||
86 | .name = "s2mpa01-pmic", | ||
87 | }, | ||
88 | }; | ||
89 | |||
70 | #ifdef CONFIG_OF | 90 | #ifdef CONFIG_OF |
71 | static struct of_device_id sec_dt_match[] = { | 91 | static struct of_device_id sec_dt_match[] = { |
72 | { .compatible = "samsung,s5m8767-pmic", | 92 | { .compatible = "samsung,s5m8767-pmic", |
73 | .data = (void *)S5M8767X, | 93 | .data = (void *)S5M8767X, |
74 | }, | 94 | }, { |
75 | { .compatible = "samsung,s2mps11-pmic", | 95 | .compatible = "samsung,s2mps11-pmic", |
76 | .data = (void *)S2MPS11X, | 96 | .data = (void *)S2MPS11X, |
97 | }, { | ||
98 | .compatible = "samsung,s2mps14-pmic", | ||
99 | .data = (void *)S2MPS14X, | ||
100 | }, { | ||
101 | .compatible = "samsung,s2mpa01-pmic", | ||
102 | .data = (void *)S2MPA01, | ||
103 | }, { | ||
104 | /* Sentinel */ | ||
77 | }, | 105 | }, |
78 | {}, | ||
79 | }; | 106 | }; |
80 | #endif | 107 | #endif |
81 | 108 | ||
109 | static bool s2mpa01_volatile(struct device *dev, unsigned int reg) | ||
110 | { | ||
111 | switch (reg) { | ||
112 | case S2MPA01_REG_INT1M: | ||
113 | case S2MPA01_REG_INT2M: | ||
114 | case S2MPA01_REG_INT3M: | ||
115 | return false; | ||
116 | default: | ||
117 | return true; | ||
118 | } | ||
119 | } | ||
120 | |||
82 | static bool s2mps11_volatile(struct device *dev, unsigned int reg) | 121 | static bool s2mps11_volatile(struct device *dev, unsigned int reg) |
83 | { | 122 | { |
84 | switch (reg) { | 123 | switch (reg) { |
@@ -104,12 +143,21 @@ static bool s5m8763_volatile(struct device *dev, unsigned int reg) | |||
104 | } | 143 | } |
105 | } | 144 | } |
106 | 145 | ||
107 | static struct regmap_config sec_regmap_config = { | 146 | static const struct regmap_config sec_regmap_config = { |
108 | .reg_bits = 8, | 147 | .reg_bits = 8, |
109 | .val_bits = 8, | 148 | .val_bits = 8, |
110 | }; | 149 | }; |
111 | 150 | ||
112 | static struct regmap_config s2mps11_regmap_config = { | 151 | static const struct regmap_config s2mpa01_regmap_config = { |
152 | .reg_bits = 8, | ||
153 | .val_bits = 8, | ||
154 | |||
155 | .max_register = S2MPA01_REG_LDO_OVCB4, | ||
156 | .volatile_reg = s2mpa01_volatile, | ||
157 | .cache_type = REGCACHE_FLAT, | ||
158 | }; | ||
159 | |||
160 | static const struct regmap_config s2mps11_regmap_config = { | ||
113 | .reg_bits = 8, | 161 | .reg_bits = 8, |
114 | .val_bits = 8, | 162 | .val_bits = 8, |
115 | 163 | ||
@@ -118,7 +166,16 @@ static struct regmap_config s2mps11_regmap_config = { | |||
118 | .cache_type = REGCACHE_FLAT, | 166 | .cache_type = REGCACHE_FLAT, |
119 | }; | 167 | }; |
120 | 168 | ||
121 | static struct regmap_config s5m8763_regmap_config = { | 169 | static const struct regmap_config s2mps14_regmap_config = { |
170 | .reg_bits = 8, | ||
171 | .val_bits = 8, | ||
172 | |||
173 | .max_register = S2MPS14_REG_LDODSCH3, | ||
174 | .volatile_reg = s2mps11_volatile, | ||
175 | .cache_type = REGCACHE_FLAT, | ||
176 | }; | ||
177 | |||
178 | static const struct regmap_config s5m8763_regmap_config = { | ||
122 | .reg_bits = 8, | 179 | .reg_bits = 8, |
123 | .val_bits = 8, | 180 | .val_bits = 8, |
124 | 181 | ||
@@ -127,7 +184,7 @@ static struct regmap_config s5m8763_regmap_config = { | |||
127 | .cache_type = REGCACHE_FLAT, | 184 | .cache_type = REGCACHE_FLAT, |
128 | }; | 185 | }; |
129 | 186 | ||
130 | static struct regmap_config s5m8767_regmap_config = { | 187 | static const struct regmap_config s5m8767_regmap_config = { |
131 | .reg_bits = 8, | 188 | .reg_bits = 8, |
132 | .val_bits = 8, | 189 | .val_bits = 8, |
133 | 190 | ||
@@ -136,9 +193,18 @@ static struct regmap_config s5m8767_regmap_config = { | |||
136 | .cache_type = REGCACHE_FLAT, | 193 | .cache_type = REGCACHE_FLAT, |
137 | }; | 194 | }; |
138 | 195 | ||
139 | static const struct regmap_config sec_rtc_regmap_config = { | 196 | static const struct regmap_config s5m_rtc_regmap_config = { |
140 | .reg_bits = 8, | 197 | .reg_bits = 8, |
141 | .val_bits = 8, | 198 | .val_bits = 8, |
199 | |||
200 | .max_register = SEC_RTC_REG_MAX, | ||
201 | }; | ||
202 | |||
203 | static const struct regmap_config s2mps14_rtc_regmap_config = { | ||
204 | .reg_bits = 8, | ||
205 | .val_bits = 8, | ||
206 | |||
207 | .max_register = S2MPS_RTC_REG_MAX, | ||
142 | }; | 208 | }; |
143 | 209 | ||
144 | #ifdef CONFIG_OF | 210 | #ifdef CONFIG_OF |
@@ -174,28 +240,28 @@ static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( | |||
174 | static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( | 240 | static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( |
175 | struct device *dev) | 241 | struct device *dev) |
176 | { | 242 | { |
177 | return 0; | 243 | return NULL; |
178 | } | 244 | } |
179 | #endif | 245 | #endif |
180 | 246 | ||
181 | static inline int sec_i2c_get_driver_data(struct i2c_client *i2c, | 247 | static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c, |
182 | const struct i2c_device_id *id) | 248 | const struct i2c_device_id *id) |
183 | { | 249 | { |
184 | #ifdef CONFIG_OF | 250 | #ifdef CONFIG_OF |
185 | if (i2c->dev.of_node) { | 251 | if (i2c->dev.of_node) { |
186 | const struct of_device_id *match; | 252 | const struct of_device_id *match; |
187 | match = of_match_node(sec_dt_match, i2c->dev.of_node); | 253 | match = of_match_node(sec_dt_match, i2c->dev.of_node); |
188 | return (int)match->data; | 254 | return (unsigned long)match->data; |
189 | } | 255 | } |
190 | #endif | 256 | #endif |
191 | return (int)id->driver_data; | 257 | return id->driver_data; |
192 | } | 258 | } |
193 | 259 | ||
194 | static int sec_pmic_probe(struct i2c_client *i2c, | 260 | static int sec_pmic_probe(struct i2c_client *i2c, |
195 | const struct i2c_device_id *id) | 261 | const struct i2c_device_id *id) |
196 | { | 262 | { |
197 | struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); | 263 | struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); |
198 | const struct regmap_config *regmap; | 264 | const struct regmap_config *regmap, *regmap_rtc; |
199 | struct sec_pmic_dev *sec_pmic; | 265 | struct sec_pmic_dev *sec_pmic; |
200 | int ret; | 266 | int ret; |
201 | 267 | ||
@@ -227,17 +293,34 @@ static int sec_pmic_probe(struct i2c_client *i2c, | |||
227 | } | 293 | } |
228 | 294 | ||
229 | switch (sec_pmic->device_type) { | 295 | switch (sec_pmic->device_type) { |
296 | case S2MPA01: | ||
297 | regmap = &s2mpa01_regmap_config; | ||
298 | break; | ||
230 | case S2MPS11X: | 299 | case S2MPS11X: |
231 | regmap = &s2mps11_regmap_config; | 300 | regmap = &s2mps11_regmap_config; |
301 | /* | ||
302 | * The rtc-s5m driver does not support S2MPS11 and there | ||
303 | * is no mfd_cell for S2MPS11 RTC device. | ||
304 | * However we must pass something to devm_regmap_init_i2c() | ||
305 | * so use S5M-like regmap config even though it wouldn't work. | ||
306 | */ | ||
307 | regmap_rtc = &s5m_rtc_regmap_config; | ||
308 | break; | ||
309 | case S2MPS14X: | ||
310 | regmap = &s2mps14_regmap_config; | ||
311 | regmap_rtc = &s2mps14_rtc_regmap_config; | ||
232 | break; | 312 | break; |
233 | case S5M8763X: | 313 | case S5M8763X: |
234 | regmap = &s5m8763_regmap_config; | 314 | regmap = &s5m8763_regmap_config; |
315 | regmap_rtc = &s5m_rtc_regmap_config; | ||
235 | break; | 316 | break; |
236 | case S5M8767X: | 317 | case S5M8767X: |
237 | regmap = &s5m8767_regmap_config; | 318 | regmap = &s5m8767_regmap_config; |
319 | regmap_rtc = &s5m_rtc_regmap_config; | ||
238 | break; | 320 | break; |
239 | default: | 321 | default: |
240 | regmap = &sec_regmap_config; | 322 | regmap = &sec_regmap_config; |
323 | regmap_rtc = &s5m_rtc_regmap_config; | ||
241 | break; | 324 | break; |
242 | } | 325 | } |
243 | 326 | ||
@@ -250,10 +333,13 @@ static int sec_pmic_probe(struct i2c_client *i2c, | |||
250 | } | 333 | } |
251 | 334 | ||
252 | sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); | 335 | sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); |
336 | if (!sec_pmic->rtc) { | ||
337 | dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n"); | ||
338 | return -ENODEV; | ||
339 | } | ||
253 | i2c_set_clientdata(sec_pmic->rtc, sec_pmic); | 340 | i2c_set_clientdata(sec_pmic->rtc, sec_pmic); |
254 | 341 | ||
255 | sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, | 342 | sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc); |
256 | &sec_rtc_regmap_config); | ||
257 | if (IS_ERR(sec_pmic->regmap_rtc)) { | 343 | if (IS_ERR(sec_pmic->regmap_rtc)) { |
258 | ret = PTR_ERR(sec_pmic->regmap_rtc); | 344 | ret = PTR_ERR(sec_pmic->regmap_rtc); |
259 | dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n", | 345 | dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n", |
@@ -281,10 +367,18 @@ static int sec_pmic_probe(struct i2c_client *i2c, | |||
281 | ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs, | 367 | ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs, |
282 | ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL); | 368 | ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL); |
283 | break; | 369 | break; |
370 | case S2MPA01: | ||
371 | ret = mfd_add_devices(sec_pmic->dev, -1, s2mpa01_devs, | ||
372 | ARRAY_SIZE(s2mpa01_devs), NULL, 0, NULL); | ||
373 | break; | ||
284 | case S2MPS11X: | 374 | case S2MPS11X: |
285 | ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs, | 375 | ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs, |
286 | ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL); | 376 | ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL); |
287 | break; | 377 | break; |
378 | case S2MPS14X: | ||
379 | ret = mfd_add_devices(sec_pmic->dev, -1, s2mps14_devs, | ||
380 | ARRAY_SIZE(s2mps14_devs), NULL, 0, NULL); | ||
381 | break; | ||
288 | default: | 382 | default: |
289 | /* If this happens the probe function is problem */ | 383 | /* If this happens the probe function is problem */ |
290 | BUG(); | 384 | BUG(); |
@@ -293,6 +387,8 @@ static int sec_pmic_probe(struct i2c_client *i2c, | |||
293 | if (ret) | 387 | if (ret) |
294 | goto err; | 388 | goto err; |
295 | 389 | ||
390 | device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup); | ||
391 | |||
296 | return ret; | 392 | return ret; |
297 | 393 | ||
298 | err: | 394 | err: |
@@ -311,6 +407,45 @@ static int sec_pmic_remove(struct i2c_client *i2c) | |||
311 | return 0; | 407 | return 0; |
312 | } | 408 | } |
313 | 409 | ||
410 | #ifdef CONFIG_PM_SLEEP | ||
411 | static int sec_pmic_suspend(struct device *dev) | ||
412 | { | ||
413 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
414 | struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); | ||
415 | |||
416 | if (device_may_wakeup(dev)) { | ||
417 | enable_irq_wake(sec_pmic->irq); | ||
418 | /* | ||
419 | * PMIC IRQ must be disabled during suspend for RTC alarm | ||
420 | * to work properly. | ||
421 | * When device is woken up from suspend by RTC Alarm, an | ||
422 | * interrupt occurs before resuming I2C bus controller. | ||
423 | * The interrupt is handled by regmap_irq_thread which tries | ||
424 | * to read RTC registers. This read fails (I2C is still | ||
425 | * suspended) and RTC Alarm interrupt is disabled. | ||
426 | */ | ||
427 | disable_irq(sec_pmic->irq); | ||
428 | } | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static int sec_pmic_resume(struct device *dev) | ||
434 | { | ||
435 | struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); | ||
436 | struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); | ||
437 | |||
438 | if (device_may_wakeup(dev)) { | ||
439 | disable_irq_wake(sec_pmic->irq); | ||
440 | enable_irq(sec_pmic->irq); | ||
441 | } | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | #endif /* CONFIG_PM_SLEEP */ | ||
446 | |||
447 | static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume); | ||
448 | |||
314 | static const struct i2c_device_id sec_pmic_id[] = { | 449 | static const struct i2c_device_id sec_pmic_id[] = { |
315 | { "sec_pmic", 0 }, | 450 | { "sec_pmic", 0 }, |
316 | { } | 451 | { } |
@@ -321,6 +456,7 @@ static struct i2c_driver sec_pmic_driver = { | |||
321 | .driver = { | 456 | .driver = { |
322 | .name = "sec_pmic", | 457 | .name = "sec_pmic", |
323 | .owner = THIS_MODULE, | 458 | .owner = THIS_MODULE, |
459 | .pm = &sec_pmic_pm_ops, | ||
324 | .of_match_table = of_match_ptr(sec_dt_match), | 460 | .of_match_table = of_match_ptr(sec_dt_match), |
325 | }, | 461 | }, |
326 | .probe = sec_pmic_probe, | 462 | .probe = sec_pmic_probe, |