diff options
author | Josh Cartwright <joshc@codeaurora.org> | 2014-04-03 17:50:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-03 19:21:23 -0400 |
commit | 5a418558cdae4fd0699b7b6a960f03a8bb38a338 (patch) | |
tree | 7aafafb5e5993af52b0b0014a80574a8b0f8d8d0 /drivers/rtc/rtc-pm8xxx.c | |
parent | bffcbc0887a7496c19639d55ff0e7483ee17aa42 (diff) |
rtc: pm8xxx: add support for devicetree
Add support for describing the PM8921/PM8058 RTC in device tree.
Additionally:
- drop support for describing the RTC using platform data,
as there are no current in tree users who do so.
- make allow_set_time a device-specific flag, instead of mucking
with the rtc_ops
Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc/rtc-pm8xxx.c')
-rw-r--r-- | drivers/rtc/rtc-pm8xxx.c | 52 |
1 files changed, 29 insertions, 23 deletions
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 91ac2e346aea..6e3cd345379d 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | * GNU General Public License for more details. | 10 | * GNU General Public License for more details. |
11 | */ | 11 | */ |
12 | 12 | #include <linux/of.h> | |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/rtc.h> | 15 | #include <linux/rtc.h> |
@@ -19,9 +19,6 @@ | |||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | 21 | ||
22 | #include <linux/mfd/pm8xxx/rtc.h> | ||
23 | |||
24 | |||
25 | /* RTC Register offsets from RTC CTRL REG */ | 22 | /* RTC Register offsets from RTC CTRL REG */ |
26 | #define PM8XXX_ALARM_CTRL_OFFSET 0x01 | 23 | #define PM8XXX_ALARM_CTRL_OFFSET 0x01 |
27 | #define PM8XXX_RTC_WRITE_OFFSET 0x02 | 24 | #define PM8XXX_RTC_WRITE_OFFSET 0x02 |
@@ -39,6 +36,7 @@ | |||
39 | * struct pm8xxx_rtc - rtc driver internal structure | 36 | * struct pm8xxx_rtc - rtc driver internal structure |
40 | * @rtc: rtc device for this driver. | 37 | * @rtc: rtc device for this driver. |
41 | * @regmap: regmap used to access RTC registers | 38 | * @regmap: regmap used to access RTC registers |
39 | * @allow_set_time: indicates whether writing to the RTC is allowed | ||
42 | * @rtc_alarm_irq: rtc alarm irq number. | 40 | * @rtc_alarm_irq: rtc alarm irq number. |
43 | * @rtc_base: address of rtc control register. | 41 | * @rtc_base: address of rtc control register. |
44 | * @rtc_read_base: base address of read registers. | 42 | * @rtc_read_base: base address of read registers. |
@@ -51,6 +49,7 @@ | |||
51 | struct pm8xxx_rtc { | 49 | struct pm8xxx_rtc { |
52 | struct rtc_device *rtc; | 50 | struct rtc_device *rtc; |
53 | struct regmap *regmap; | 51 | struct regmap *regmap; |
52 | bool allow_set_time; | ||
54 | int rtc_alarm_irq; | 53 | int rtc_alarm_irq; |
55 | int rtc_base; | 54 | int rtc_base; |
56 | int rtc_read_base; | 55 | int rtc_read_base; |
@@ -75,6 +74,9 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
75 | u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, ctrl_reg; | 74 | u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, ctrl_reg; |
76 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); | 75 | struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); |
77 | 76 | ||
77 | if (!rtc_dd->allow_set_time) | ||
78 | return -EACCES; | ||
79 | |||
78 | rtc_tm_to_time(tm, &secs); | 80 | rtc_tm_to_time(tm, &secs); |
79 | 81 | ||
80 | for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { | 82 | for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { |
@@ -298,8 +300,9 @@ rtc_rw_fail: | |||
298 | return rc; | 300 | return rc; |
299 | } | 301 | } |
300 | 302 | ||
301 | static struct rtc_class_ops pm8xxx_rtc_ops = { | 303 | static const struct rtc_class_ops pm8xxx_rtc_ops = { |
302 | .read_time = pm8xxx_rtc_read_time, | 304 | .read_time = pm8xxx_rtc_read_time, |
305 | .set_time = pm8xxx_rtc_set_time, | ||
303 | .set_alarm = pm8xxx_rtc_set_alarm, | 306 | .set_alarm = pm8xxx_rtc_set_alarm, |
304 | .read_alarm = pm8xxx_rtc_read_alarm, | 307 | .read_alarm = pm8xxx_rtc_read_alarm, |
305 | .alarm_irq_enable = pm8xxx_rtc_alarm_irq_enable, | 308 | .alarm_irq_enable = pm8xxx_rtc_alarm_irq_enable, |
@@ -353,18 +356,26 @@ rtc_alarm_handled: | |||
353 | return IRQ_HANDLED; | 356 | return IRQ_HANDLED; |
354 | } | 357 | } |
355 | 358 | ||
359 | /* | ||
360 | * Hardcoded RTC bases until IORESOURCE_REG mapping is figured out | ||
361 | */ | ||
362 | static const struct of_device_id pm8xxx_id_table[] = { | ||
363 | { .compatible = "qcom,pm8921-rtc", .data = (void *) 0x11D }, | ||
364 | { .compatible = "qcom,pm8058-rtc", .data = (void *) 0x1E8 }, | ||
365 | { }, | ||
366 | }; | ||
367 | MODULE_DEVICE_TABLE(of, pm8xxx_id_table); | ||
368 | |||
356 | static int pm8xxx_rtc_probe(struct platform_device *pdev) | 369 | static int pm8xxx_rtc_probe(struct platform_device *pdev) |
357 | { | 370 | { |
358 | int rc; | 371 | int rc; |
359 | unsigned int ctrl_reg; | 372 | unsigned int ctrl_reg; |
360 | bool rtc_write_enable = false; | ||
361 | struct pm8xxx_rtc *rtc_dd; | 373 | struct pm8xxx_rtc *rtc_dd; |
362 | struct resource *rtc_resource; | 374 | const struct of_device_id *match; |
363 | const struct pm8xxx_rtc_platform_data *pdata = | ||
364 | dev_get_platdata(&pdev->dev); | ||
365 | 375 | ||
366 | if (pdata != NULL) | 376 | match = of_match_node(pm8xxx_id_table, pdev->dev.of_node); |
367 | rtc_write_enable = pdata->rtc_write_enable; | 377 | if (!match) |
378 | return -ENXIO; | ||
368 | 379 | ||
369 | rtc_dd = devm_kzalloc(&pdev->dev, sizeof(*rtc_dd), GFP_KERNEL); | 380 | rtc_dd = devm_kzalloc(&pdev->dev, sizeof(*rtc_dd), GFP_KERNEL); |
370 | if (rtc_dd == NULL) | 381 | if (rtc_dd == NULL) |
@@ -385,14 +396,10 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) | |||
385 | return -ENXIO; | 396 | return -ENXIO; |
386 | } | 397 | } |
387 | 398 | ||
388 | rtc_resource = platform_get_resource_byname(pdev, IORESOURCE_IO, | 399 | rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node, |
389 | "pmic_rtc_base"); | 400 | "allow-set-time"); |
390 | if (!(rtc_resource && rtc_resource->start)) { | ||
391 | dev_err(&pdev->dev, "RTC IO resource absent!\n"); | ||
392 | return -ENXIO; | ||
393 | } | ||
394 | 401 | ||
395 | rtc_dd->rtc_base = rtc_resource->start; | 402 | rtc_dd->rtc_base = (long) match->data; |
396 | 403 | ||
397 | /* Setup RTC register addresses */ | 404 | /* Setup RTC register addresses */ |
398 | rtc_dd->rtc_write_base = rtc_dd->rtc_base + PM8XXX_RTC_WRITE_OFFSET; | 405 | rtc_dd->rtc_write_base = rtc_dd->rtc_base + PM8XXX_RTC_WRITE_OFFSET; |
@@ -419,8 +426,6 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) | |||
419 | } | 426 | } |
420 | 427 | ||
421 | rtc_dd->ctrl_reg = ctrl_reg; | 428 | rtc_dd->ctrl_reg = ctrl_reg; |
422 | if (rtc_write_enable) | ||
423 | pm8xxx_rtc_ops.set_time = pm8xxx_rtc_set_time; | ||
424 | 429 | ||
425 | platform_set_drvdata(pdev, rtc_dd); | 430 | platform_set_drvdata(pdev, rtc_dd); |
426 | 431 | ||
@@ -479,9 +484,10 @@ static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, | |||
479 | static struct platform_driver pm8xxx_rtc_driver = { | 484 | static struct platform_driver pm8xxx_rtc_driver = { |
480 | .probe = pm8xxx_rtc_probe, | 485 | .probe = pm8xxx_rtc_probe, |
481 | .driver = { | 486 | .driver = { |
482 | .name = PM8XXX_RTC_DEV_NAME, | 487 | .name = "rtc-pm8xxx", |
483 | .owner = THIS_MODULE, | 488 | .owner = THIS_MODULE, |
484 | .pm = &pm8xxx_rtc_pm_ops, | 489 | .pm = &pm8xxx_rtc_pm_ops, |
490 | .of_match_table = pm8xxx_id_table, | ||
485 | }, | 491 | }, |
486 | }; | 492 | }; |
487 | 493 | ||