summaryrefslogtreecommitdiff
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig11
-rw-r--r--drivers/rtc/qpnp-rtc.c168
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);