]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - drivers/rtc/rtc-bd70528.c
rtc: bd70528: Support RTC on ROHM BD71815
[mirror_ubuntu-jammy-kernel.git] / drivers / rtc / rtc-bd70528.c
index 17cb67f5bf6e2168b5e45653f4cb585b38b0d61d..6454afca02a6b4947fdb62cb888a1a7c7f0930af 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/bcd.h>
 #include <linux/mfd/rohm-bd70528.h>
+#include <linux/mfd/rohm-bd71815.h>
 #include <linux/mfd/rohm-bd71828.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
 #include <linux/rtc.h>
 
+/*
+ * On BD71828 and BD71815 the ALM0 MASK is 14 bytes after the ALM0
+ * block start
+ */
+#define BD718XX_ALM_EN_OFFSET 14
+
 /*
  * We read regs RTC_SEC => RTC_YEAR
  * this struct is ordered according to chip registers.
@@ -52,8 +59,10 @@ struct bd70528_rtc_alm {
 
 struct bd70528_rtc {
        struct rohm_regmap_dev *parent;
+       struct regmap *regmap;
        struct device *dev;
        u8 reg_time_start;
+       u8 bd718xx_alm_block_start;
        bool has_rtc_timers;
 };
 
@@ -234,10 +243,9 @@ static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a)
        int ret;
        struct bd71828_rtc_alm alm;
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
 
-       ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
-                              &alm, sizeof(alm));
+       ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, &alm,
+                              sizeof(alm));
        if (ret) {
                dev_err(dev, "Failed to read alarm regs\n");
                return ret;
@@ -250,8 +258,8 @@ static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a)
        else
                alm.alm_mask |= BD70528_MASK_ALM_EN;
 
-       ret = regmap_bulk_write(parent->regmap, BD71828_REG_RTC_ALM_START,
-                               &alm, sizeof(alm));
+       ret = regmap_bulk_write(r->regmap, r->bd718xx_alm_block_start, &alm,
+                               sizeof(alm));
        if (ret)
                dev_err(dev, "Failed to set alarm time\n");
 
@@ -265,17 +273,16 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
        struct bd70528_rtc_alm alm;
        int ret;
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
 
-       ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_WAKE_START,
-                              &wake, sizeof(wake));
+       ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_WAKE_START, &wake,
+                              sizeof(wake));
        if (ret) {
                dev_err(dev, "Failed to read wake regs\n");
                return ret;
        }
 
-       ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
-                              &alm, sizeof(alm));
+       ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, &alm,
+                              sizeof(alm));
        if (ret) {
                dev_err(dev, "Failed to read alarm regs\n");
                return ret;
@@ -292,15 +299,14 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
                wake.ctrl &= ~BD70528_MASK_WAKE_EN;
        }
 
-       ret = regmap_bulk_write(parent->regmap,
-                               BD70528_REG_RTC_WAKE_START, &wake,
+       ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_WAKE_START, &wake,
                                sizeof(wake));
        if (ret) {
                dev_err(dev, "Failed to set wake time\n");
                return ret;
        }
-       ret = regmap_bulk_write(parent->regmap, BD70528_REG_RTC_ALM_START,
-                               &alm, sizeof(alm));
+       ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_ALM_START, &alm,
+                               sizeof(alm));
        if (ret)
                dev_err(dev, "Failed to set alarm time\n");
 
@@ -312,10 +318,9 @@ static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a)
        int ret;
        struct bd71828_rtc_alm alm;
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
 
-       ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
-                              &alm, sizeof(alm));
+       ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, &alm,
+                              sizeof(alm));
        if (ret) {
                dev_err(dev, "Failed to read alarm regs\n");
                return ret;
@@ -336,10 +341,9 @@ static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a)
        struct bd70528_rtc_alm alm;
        int ret;
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
 
-       ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
-                              &alm, sizeof(alm));
+       ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, &alm,
+                              sizeof(alm));
        if (ret) {
                dev_err(dev, "Failed to read alarm regs\n");
                return ret;
@@ -360,14 +364,12 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
        int ret, tmpret, old_states;
        struct bd70528_rtc_data rtc_data;
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
 
        ret = bd70528_disable_rtc_based_timers(r, &old_states);
        if (ret)
                return ret;
 
-       tmpret = regmap_bulk_read(parent->regmap,
-                                 r->reg_time_start, &rtc_data,
+       tmpret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data,
                                  sizeof(rtc_data));
        if (tmpret) {
                dev_err(dev, "Failed to read RTC time registers\n");
@@ -375,8 +377,7 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
        }
        tm2rtc(t, &rtc_data);
 
-       tmpret = regmap_bulk_write(parent->regmap,
-                                  r->reg_time_start, &rtc_data,
+       tmpret = regmap_bulk_write(r->regmap, r->reg_time_start, &rtc_data,
                                   sizeof(rtc_data));
        if (tmpret) {
                dev_err(dev, "Failed to set RTC time\n");
@@ -410,13 +411,11 @@ static int bd70528_set_time(struct device *dev, struct rtc_time *t)
 static int bd70528_get_time(struct device *dev, struct rtc_time *t)
 {
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
        struct bd70528_rtc_data rtc_data;
        int ret;
 
        /* read the RTC date and time registers all at once */
-       ret = regmap_bulk_read(parent->regmap,
-                              r->reg_time_start, &rtc_data,
+       ret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data,
                               sizeof(rtc_data));
        if (ret) {
                dev_err(dev, "Failed to read RTC time (err %d)\n", ret);
@@ -443,7 +442,7 @@ static int bd70528_alm_enable(struct device *dev, unsigned int enabled)
                dev_err(dev, "Failed to change wake state\n");
                goto out_unlock;
        }
-       ret = regmap_update_bits(r->parent->regmap, BD70528_REG_RTC_ALM_MASK,
+       ret = regmap_update_bits(r->regmap, BD70528_REG_RTC_ALM_MASK,
                                 BD70528_MASK_ALM_EN, enableval);
        if (ret)
                dev_err(dev, "Failed to change alarm state\n");
@@ -462,8 +461,9 @@ static int bd71828_alm_enable(struct device *dev, unsigned int enabled)
        if (!enabled)
                enableval = 0;
 
-       ret = regmap_update_bits(r->parent->regmap, BD71828_REG_RTC_ALM0_MASK,
-                                BD70528_MASK_ALM_EN, enableval);
+       ret = regmap_update_bits(r->regmap, r->bd718xx_alm_block_start +
+                                BD718XX_ALM_EN_OFFSET, BD70528_MASK_ALM_EN,
+                                enableval);
        if (ret)
                dev_err(dev, "Failed to change alarm state\n");
 
@@ -498,7 +498,6 @@ static int bd70528_probe(struct platform_device *pdev)
 {
        struct bd70528_rtc *bd_rtc;
        const struct rtc_class_ops *rtc_ops;
-       struct rohm_regmap_dev *parent;
        const char *irq_name;
        int ret;
        struct rtc_device *rtc;
@@ -508,20 +507,25 @@ static int bd70528_probe(struct platform_device *pdev)
        u8 hour_reg;
        enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
 
-       parent = dev_get_drvdata(pdev->dev.parent);
-       if (!parent) {
-               dev_err(&pdev->dev, "No MFD driver data\n");
-               return -EINVAL;
-       }
        bd_rtc = devm_kzalloc(&pdev->dev, sizeof(*bd_rtc), GFP_KERNEL);
        if (!bd_rtc)
                return -ENOMEM;
 
-       bd_rtc->parent = parent;
+       bd_rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!bd_rtc->regmap) {
+               dev_err(&pdev->dev, "No regmap\n");
+               return -EINVAL;
+       }
+
        bd_rtc->dev = &pdev->dev;
 
        switch (chip) {
        case ROHM_CHIP_TYPE_BD70528:
+               bd_rtc->parent = dev_get_drvdata(pdev->dev.parent);
+               if (!bd_rtc->parent) {
+                       dev_err(&pdev->dev, "No MFD data\n");
+                       return -EINVAL;
+               }
                irq_name = "bd70528-rtc-alm";
                bd_rtc->has_rtc_timers = true;
                bd_rtc->reg_time_start = BD70528_REG_RTC_START;
@@ -529,9 +533,28 @@ static int bd70528_probe(struct platform_device *pdev)
                enable_main_irq = true;
                rtc_ops = &bd70528_rtc_ops;
                break;
+       case ROHM_CHIP_TYPE_BD71815:
+               irq_name = "bd71815-rtc-alm-0";
+               bd_rtc->reg_time_start = BD71815_REG_RTC_START;
+
+               /*
+                * See also BD718XX_ALM_EN_OFFSET:
+                * This works for BD71828 and BD71815 as they have same offset
+                * between ALM0 start and ALM0_MASK. If new ICs are to be
+                * added this requires proper check as ALM0_MASK is not located
+                * at the end of ALM0 block - but after all ALM blocks so if
+                * amount of ALMs differ the offset to enable/disable is likely
+                * to be incorrect and enable/disable must be given as own
+                * reg address here.
+                */
+               bd_rtc->bd718xx_alm_block_start = BD71815_REG_RTC_ALM_START;
+               hour_reg = BD71815_REG_HOUR;
+               rtc_ops = &bd71828_rtc_ops;
+               break;
        case ROHM_CHIP_TYPE_BD71828:
                irq_name = "bd71828-rtc-alm-0";
                bd_rtc->reg_time_start = BD71828_REG_RTC_START;
+               bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START;
                hour_reg = BD71828_REG_RTC_HOUR;
                rtc_ops = &bd71828_rtc_ops;
                break;
@@ -547,7 +570,7 @@ static int bd70528_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, bd_rtc);
 
-       ret = regmap_read(parent->regmap, hour_reg, &hr);
+       ret = regmap_read(bd_rtc->regmap, hour_reg, &hr);
 
        if (ret) {
                dev_err(&pdev->dev, "Failed to reag RTC clock\n");
@@ -595,7 +618,7 @@ static int bd70528_probe(struct platform_device *pdev)
         *  from sub-registers when IRQ is disabled or freed.
         */
        if (enable_main_irq) {
-               ret = regmap_update_bits(parent->regmap,
+               ret = regmap_update_bits(bd_rtc->regmap,
                                 BD70528_REG_INT_MAIN_MASK,
                                 BD70528_INT_RTC_MASK, 0);
                if (ret) {
@@ -610,6 +633,7 @@ static int bd70528_probe(struct platform_device *pdev)
 static const struct platform_device_id bd718x7_rtc_id[] = {
        { "bd70528-rtc", ROHM_CHIP_TYPE_BD70528 },
        { "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 },
+       { "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 },
        { },
 };
 MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id);