@@ -3,6 +3,7 @@
// Copyright (c) 2021 Samuel Holland <samuel@sholland.org>
//
+#include <linux/auxiliary_bus.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
@@ -11,8 +12,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/clk/sunxi-ng.h>
-
#include "ccu_common.h"
#include "ccu_div.h"
@@ -44,6 +43,8 @@
#define DCXO_CTRL_REG 0x160
#define DCXO_CTRL_CLK16M_RC_EN BIT(0)
+#define SUN6I_RTC_AUX_ID(_name) "rtc_sun6i." #_name
+
struct sun6i_rtc_match_data {
bool have_ext_osc32k : 1;
bool have_iosc_calibration : 1;
@@ -349,14 +350,18 @@ static const struct of_device_id sun6i_rtc_ccu_match[] = {
};
MODULE_DEVICE_TABLE(of, sun6i_rtc_ccu_match);
-int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
+static int sun6i_rtc_ccu_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
{
const struct sun6i_rtc_match_data *data;
struct clk *ext_osc32k_clk = NULL;
const struct of_device_id *match;
+ struct device *dev = &adev->dev;
+ void __iomem *reg = dev->platform_data;
+ struct device *parent = dev->parent;
/* This driver is only used for newer variants of the hardware. */
- match = of_match_device(sun6i_rtc_ccu_match, dev);
+ match = of_match_device(sun6i_rtc_ccu_match, parent);
if (!match)
return 0;
@@ -367,9 +372,9 @@ int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
const char *fw_name;
/* ext-osc32k was the only input clock in the old binding. */
- fw_name = of_property_present(dev->of_node, "clock-names")
+ fw_name = of_property_present(parent->of_node, "clock-names")
? "ext-osc32k" : NULL;
- ext_osc32k_clk = devm_clk_get_optional(dev, fw_name);
+ ext_osc32k_clk = devm_clk_get_optional(parent, fw_name);
if (IS_ERR(ext_osc32k_clk))
return PTR_ERR(ext_osc32k_clk);
}
@@ -392,6 +397,18 @@ int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
return devm_sunxi_ccu_probe(dev, reg, &sun6i_rtc_ccu_desc);
}
+static const struct auxiliary_device_id sun6i_ccu_rtc_ids[] = {
+ { .name = SUN6I_RTC_AUX_ID(sun6i) },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(auxiliary, sun6i_ccu_rtc_ids);
+
+static struct auxiliary_driver sun6i_ccu_rtc_driver = {
+ .probe = sun6i_rtc_ccu_probe,
+ .id_table = sun6i_ccu_rtc_ids,
+};
+module_auxiliary_driver(sun6i_ccu_rtc_driver);
+
MODULE_IMPORT_NS("SUNXI_CCU");
MODULE_DESCRIPTION("Support for the Allwinner H616/R329 RTC CCU");
MODULE_LICENSE("GPL");
@@ -11,9 +11,9 @@
* Copyright (c) 2013, Carlo Caione <carlo.caione@gmail.com>
*/
+#include <linux/auxiliary_bus.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
-#include <linux/clk/sunxi-ng.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fs.h>
@@ -141,6 +141,11 @@ struct sun6i_rtc_clk_data {
#define RTC_LINEAR_DAY BIT(0)
+struct sun6i_rtc_match_data {
+ const char *adev_name;
+ unsigned long flags;
+};
+
struct sun6i_rtc_dev {
struct rtc_device *rtc;
const struct sun6i_rtc_clk_data *data;
@@ -745,8 +750,10 @@ static void sun6i_rtc_bus_clk_cleanup(void *data)
static int sun6i_rtc_probe(struct platform_device *pdev)
{
+ const struct sun6i_rtc_match_data *data;
struct sun6i_rtc_dev *chip = sun6i_rtc;
struct device *dev = &pdev->dev;
+ struct auxiliary_device *adev;
struct clk *bus_clk;
int ret;
@@ -765,6 +772,8 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
return ret;
}
+ data = of_device_get_match_data(&pdev->dev);
+
if (!chip) {
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
@@ -776,16 +785,17 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
if (IS_ERR(chip->base))
return PTR_ERR(chip->base);
- if (IS_REACHABLE(CONFIG_SUN6I_RTC_CCU)) {
- ret = sun6i_rtc_ccu_probe(dev, chip->base);
- if (ret)
- return ret;
+ if (data && data->adev_name) {
+ adev = devm_auxiliary_device_create(dev, data->adev_name, chip->base);
+ if (!adev)
+ return -ENODEV;
}
}
platform_set_drvdata(pdev, chip);
- chip->flags = (unsigned long)of_device_get_match_data(&pdev->dev);
+ if (data)
+ chip->flags = data->flags;
chip->irq = platform_get_irq(pdev, 0);
if (chip->irq < 0)
@@ -850,6 +860,11 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
return 0;
}
+static const struct sun6i_rtc_match_data sun6i_rtc_match_data = {
+ .adev_name = "sun6i",
+ .flags = RTC_LINEAR_DAY,
+};
+
/*
* As far as RTC functionality goes, all models are the same. The
* datasheets claim that different models have different number of
@@ -865,9 +880,9 @@ static const struct of_device_id sun6i_rtc_dt_ids[] = {
{ .compatible = "allwinner,sun50i-h5-rtc" },
{ .compatible = "allwinner,sun50i-h6-rtc" },
{ .compatible = "allwinner,sun50i-h616-rtc",
- .data = (void *)RTC_LINEAR_DAY },
+ .data = &sun6i_rtc_match_data },
{ .compatible = "allwinner,sun50i-r329-rtc",
- .data = (void *)RTC_LINEAR_DAY },
+ .data = &sun6i_rtc_match_data },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids);
@@ -9,6 +9,4 @@
int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode);
int sunxi_ccu_get_mmc_timing_mode(struct clk *clk);
-int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg);
-
#endif