diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/rtc/qpnp-rtc.c | 168 |
2 files changed, 92 insertions, 87 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index da25ffeb520d..ef3ff5e16e86 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1593,7 +1593,7 @@ config RTC_DRV_MOXART config RTC_DRV_QPNP tristate "Qualcomm QPNP PMIC RTC" - depends on (SPMI || MSM_SPMI) && OF_SPMI && MSM_QPNP_INT + depends on SPMI && OF_SPMI && MSM_QPNP_INT help Say Y here if you want to support the Qualcomm QPNP PMIC RTC. @@ -1610,6 +1610,15 @@ config RTC_DRV_MT6397 If you want to use Mediatek(R) RTC interface, select Y or M here. +config RTC_DRV_QPNP + tristate "Qualcomm QPNP PMIC RTC" + depends on SPMI + help + Say Y here if you want to support the Qualcomm QPNP PMIC RTC. + + To compile this driver as a module, choose M here: the + module will be called qpnp-rtc. + config RTC_DRV_XGENE tristate "APM X-Gene RTC" depends on HAS_IOMEM diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c index bb69b892d5e6..1b74b94796ba 100644 --- a/drivers/rtc/qpnp-rtc.c +++ b/drivers/rtc/qpnp-rtc.c @@ -11,15 +11,17 @@ */ #include <linux/module.h> +#include <linux/regmap.h> #include <linux/init.h> #include <linux/rtc.h> #include <linux/pm.h> #include <linux/slab.h> #include <linux/idr.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/spmi.h> +#include <linux/platform_device.h> #include <linux/spinlock.h> -#include <linux/spmi.h> #include <linux/alarmtimer.h> /* RTC/ALARM Register offsets */ @@ -54,27 +56,26 @@ EXPORT_SYMBOL(poweron_alarm); /* rtc driver internal structure */ struct qpnp_rtc { - u8 rtc_ctrl_reg; - u8 alarm_ctrl_reg1; - u16 rtc_base; - u16 alarm_base; - u32 rtc_write_enable; - u32 rtc_alarm_powerup; - int rtc_alarm_irq; - struct device *rtc_dev; - struct rtc_device *rtc; - struct spmi_device *spmi; - spinlock_t alarm_ctrl_lock; + u8 rtc_ctrl_reg; + u8 alarm_ctrl_reg1; + u16 rtc_base; + u16 alarm_base; + u32 rtc_write_enable; + u32 rtc_alarm_powerup; + int rtc_alarm_irq; + struct device *rtc_dev; + struct rtc_device *rtc; + struct platform_device *pdev; + struct regmap *regmap; + spinlock_t alarm_ctrl_lock; }; static int qpnp_read_wrapper(struct qpnp_rtc *rtc_dd, u8 *rtc_val, u16 base, int count) { int rc; - struct spmi_device *spmi = rtc_dd->spmi; - rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, rtc_val, - count); + rc = regmap_bulk_read(rtc_dd->regmap, base, rtc_val, count); if (rc) { dev_err(rtc_dd->rtc_dev, "SPMI read failed\n"); return rc; @@ -86,10 +87,8 @@ static int qpnp_write_wrapper(struct qpnp_rtc *rtc_dd, u8 *rtc_val, u16 base, int count) { int rc; - struct spmi_device *spmi = rtc_dd->spmi; - rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, base, rtc_val, - count); + rc = regmap_bulk_write(rtc_dd->regmap, base, rtc_val, count); if (rc) { dev_err(rtc_dd->rtc_dev, "SPMI write failed\n"); return rc; @@ -464,34 +463,38 @@ rtc_alarm_handled: return IRQ_HANDLED; } -static int qpnp_rtc_probe(struct spmi_device *spmi) +static int qpnp_rtc_probe(struct platform_device *pdev) { int rc; u8 subtype; struct qpnp_rtc *rtc_dd; - struct resource *resource; - struct spmi_resource *spmi_resource; + unsigned int base; + struct device_node *child; - rtc_dd = devm_kzalloc(&spmi->dev, sizeof(*rtc_dd), GFP_KERNEL); - if (rtc_dd == NULL) { - dev_err(&spmi->dev, "Unable to allocate memory!\n"); + rtc_dd = devm_kzalloc(&pdev->dev, sizeof(*rtc_dd), GFP_KERNEL); + if (rtc_dd == NULL) return -ENOMEM; + + rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!rtc_dd->regmap) { + dev_err(&pdev->dev, "Couldn't get parent's regmap\n"); + return -EINVAL; } /* Get the rtc write property */ - rc = of_property_read_u32(spmi->dev.of_node, "qcom,qpnp-rtc-write", + rc = of_property_read_u32(pdev->dev.of_node, "qcom,qpnp-rtc-write", &rtc_dd->rtc_write_enable); if (rc && rc != -EINVAL) { - dev_err(&spmi->dev, + dev_err(&pdev->dev, "Error reading rtc_write_enable property %d\n", rc); return rc; } - rc = of_property_read_u32(spmi->dev.of_node, + rc = of_property_read_u32(pdev->dev.of_node, "qcom,qpnp-rtc-alarm-pwrup", &rtc_dd->rtc_alarm_powerup); if (rc && rc != -EINVAL) { - dev_err(&spmi->dev, + dev_err(&pdev->dev, "Error reading rtc_alarm_powerup property %d\n", rc); return rc; } @@ -499,53 +502,49 @@ static int qpnp_rtc_probe(struct spmi_device *spmi) /* Initialise spinlock to protect RTC control register */ spin_lock_init(&rtc_dd->alarm_ctrl_lock); - rtc_dd->rtc_dev = &(spmi->dev); - rtc_dd->spmi = spmi; + rtc_dd->rtc_dev = &(pdev->dev); + rtc_dd->pdev = pdev; - /* Get RTC/ALARM resources */ - spmi_for_each_container_dev(spmi_resource, spmi) { - if (!spmi_resource) { - dev_err(&spmi->dev, - "%s: rtc_alarm: spmi resource absent!\n", - __func__); - rc = -ENXIO; - goto fail_rtc_enable; - } - resource = spmi_get_resource(spmi, spmi_resource, - IORESOURCE_MEM, 0); - if (!(resource && resource->start)) { - dev_err(&spmi->dev, - "%s: node %s IO resource absent!\n", - __func__, spmi->dev.of_node->full_name); - rc = -ENXIO; + if (of_get_available_child_count(pdev->dev.of_node) == 0) { + pr_err("no child nodes\n"); + rc = -ENXIO; + goto fail_rtc_enable; + } + + /* Get RTC/ALARM resources */ + for_each_available_child_of_node(pdev->dev.of_node, child) { + rc = of_property_read_u32(child, "reg", &base); + if (rc < 0) { + dev_err(&pdev->dev, + "Couldn't find reg in node = %s rc = %d\n", + child->full_name, rc); goto fail_rtc_enable; } rc = qpnp_read_wrapper(rtc_dd, &subtype, - resource->start + REG_OFFSET_PERP_SUBTYPE, 1); + base + REG_OFFSET_PERP_SUBTYPE, 1); if (rc) { - dev_err(&spmi->dev, + dev_err(&pdev->dev, "Peripheral subtype read failed\n"); goto fail_rtc_enable; } switch (subtype) { case RTC_PERPH_SUBTYPE: - rtc_dd->rtc_base = resource->start; + rtc_dd->rtc_base = base; break; case ALARM_PERPH_SUBTYPE: - rtc_dd->alarm_base = resource->start; - rtc_dd->rtc_alarm_irq = - spmi_get_irq(spmi, spmi_resource, 0); + rtc_dd->alarm_base = base; + rtc_dd->rtc_alarm_irq = of_irq_get(child, 0); if (rtc_dd->rtc_alarm_irq < 0) { - dev_err(&spmi->dev, "ALARM IRQ absent\n"); + dev_err(&pdev->dev, "ALARM IRQ absent\n"); rc = -ENXIO; goto fail_rtc_enable; } break; default: - dev_err(&spmi->dev, "Invalid peripheral subtype\n"); + dev_err(&pdev->dev, "Invalid peripheral subtype\n"); rc = -EINVAL; goto fail_rtc_enable; } @@ -554,22 +553,19 @@ static int qpnp_rtc_probe(struct spmi_device *spmi) rc = qpnp_read_wrapper(rtc_dd, &rtc_dd->rtc_ctrl_reg, rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1); if (rc) { - dev_err(&spmi->dev, - "Read from RTC control reg failed\n"); + dev_err(&pdev->dev, "Read from RTC control reg failed\n"); goto fail_rtc_enable; } if (!(rtc_dd->rtc_ctrl_reg & BIT_RTC_ENABLE)) { - dev_err(&spmi->dev, - "RTC h/w disabled, rtc not registered\n"); + dev_err(&pdev->dev, "RTC h/w disabled, rtc not registered\n"); goto fail_rtc_enable; } rc = qpnp_read_wrapper(rtc_dd, &rtc_dd->alarm_ctrl_reg1, rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1); if (rc) { - dev_err(&spmi->dev, - "Read from Alarm control reg failed\n"); + dev_err(&pdev->dev, "Read from Alarm control reg failed\n"); goto fail_rtc_enable; } /* Enable abort enable feature */ @@ -577,20 +573,20 @@ static int qpnp_rtc_probe(struct spmi_device *spmi) rc = qpnp_write_wrapper(rtc_dd, &rtc_dd->alarm_ctrl_reg1, rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1); if (rc) { - dev_err(&spmi->dev, "SPMI write failed!\n"); + dev_err(&pdev->dev, "SPMI write failed!\n"); goto fail_rtc_enable; } if (rtc_dd->rtc_write_enable == true) qpnp_rtc_ops.set_time = qpnp_rtc_set_time; - dev_set_drvdata(&spmi->dev, rtc_dd); + dev_set_drvdata(&pdev->dev, rtc_dd); /* Register the RTC device */ - rtc_dd->rtc = rtc_device_register("qpnp_rtc", &spmi->dev, + rtc_dd->rtc = rtc_device_register("qpnp_rtc", &pdev->dev, &qpnp_rtc_ops, THIS_MODULE); if (IS_ERR(rtc_dd->rtc)) { - dev_err(&spmi->dev, "%s: RTC registration failed (%ld)\n", + dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n", __func__, PTR_ERR(rtc_dd->rtc)); rc = PTR_ERR(rtc_dd->rtc); goto fail_rtc_enable; @@ -604,38 +600,38 @@ static int qpnp_rtc_probe(struct spmi_device *spmi) qpnp_alarm_trigger, IRQF_TRIGGER_RISING, "qpnp_rtc_alarm", rtc_dd); if (rc) { - dev_err(&spmi->dev, "Request IRQ failed (%d)\n", rc); + dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc); goto fail_req_irq; } - device_init_wakeup(&spmi->dev, 1); + device_init_wakeup(&pdev->dev, 1); enable_irq_wake(rtc_dd->rtc_alarm_irq); - dev_dbg(&spmi->dev, "Probe success !!\n"); + dev_dbg(&pdev->dev, "Probe success !!\n"); return 0; fail_req_irq: rtc_device_unregister(rtc_dd->rtc); fail_rtc_enable: - dev_set_drvdata(&spmi->dev, NULL); + dev_set_drvdata(&pdev->dev, NULL); return rc; } -static int qpnp_rtc_remove(struct spmi_device *spmi) +static int qpnp_rtc_remove(struct platform_device *pdev) { - struct qpnp_rtc *rtc_dd = dev_get_drvdata(&spmi->dev); + struct qpnp_rtc *rtc_dd = dev_get_drvdata(&pdev->dev); - device_init_wakeup(&spmi->dev, 0); + device_init_wakeup(&pdev->dev, 0); free_irq(rtc_dd->rtc_alarm_irq, rtc_dd); rtc_device_unregister(rtc_dd->rtc); - dev_set_drvdata(&spmi->dev, NULL); + dev_set_drvdata(&pdev->dev, NULL); return 0; } -static void qpnp_rtc_shutdown(struct spmi_device *spmi) +static void qpnp_rtc_shutdown(struct platform_device *pdev) { u8 value[4] = {0}; u8 reg; @@ -644,11 +640,11 @@ static void qpnp_rtc_shutdown(struct spmi_device *spmi) struct qpnp_rtc *rtc_dd; bool rtc_alarm_powerup; - if (!spmi) { + if (!pdev) { pr_err("qpnp-rtc: spmi device not found\n"); return; } - rtc_dd = dev_get_drvdata(&spmi->dev); + rtc_dd = dev_get_drvdata(&pdev->dev); if (!rtc_dd) { pr_err("qpnp-rtc: rtc driver data not found\n"); return; @@ -656,7 +652,7 @@ static void qpnp_rtc_shutdown(struct spmi_device *spmi) rtc_alarm_powerup = rtc_dd->rtc_alarm_powerup; if (!rtc_alarm_powerup && !poweron_alarm) { spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags); - dev_dbg(&spmi->dev, "Disabling alarm interrupts\n"); + dev_dbg(&pdev->dev, "Disabling alarm interrupts\n"); /* Disable RTC alarms */ reg = rtc_dd->alarm_ctrl_reg1; @@ -687,26 +683,26 @@ static struct of_device_id spmi_match_table[] = { {} }; -static struct spmi_driver qpnp_rtc_driver = { - .probe = qpnp_rtc_probe, - .remove = qpnp_rtc_remove, - .shutdown = qpnp_rtc_shutdown, - .driver = { - .name = "qcom,qpnp-rtc", - .owner = THIS_MODULE, - .of_match_table = spmi_match_table, +static struct platform_driver qpnp_rtc_driver = { + .probe = qpnp_rtc_probe, + .remove = qpnp_rtc_remove, + .shutdown = qpnp_rtc_shutdown, + .driver = { + .name = "qcom,qpnp-rtc", + .owner = THIS_MODULE, + .of_match_table = spmi_match_table, }, }; static int __init qpnp_rtc_init(void) { - return spmi_driver_register(&qpnp_rtc_driver); + return platform_driver_register(&qpnp_rtc_driver); } module_init(qpnp_rtc_init); static void __exit qpnp_rtc_exit(void) { - spmi_driver_unregister(&qpnp_rtc_driver); + platform_driver_unregister(&qpnp_rtc_driver); } module_exit(qpnp_rtc_exit); |
