summaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-sun6i.c
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@free-electrons.com>2017-08-25 09:42:02 +0200
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>2017-09-01 01:10:19 +0200
commit17ecd246414b3a0fe0cb248c86977a8bda465b7b (patch)
tree56b0293083715c235cef9e312434cfbc200e2497 /drivers/rtc/rtc-sun6i.c
parentrtc: goldfish: Add RTC driver for Android emulator (diff)
downloadlinux-17ecd246414b3a0fe0cb248c86977a8bda465b7b.tar.xz
linux-17ecd246414b3a0fe0cb248c86977a8bda465b7b.zip
rtc: sun6i: Add support for the external oscillator gate
The RTC can output its 32kHz clock outside of the SoC, for example to clock a WiFi chip. Create a new clock that other devices will be able to retrieve, while maintaining the DT stability by providing a default name for that clock if clock-output-names doesn't list one. Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/rtc/rtc-sun6i.c')
-rw-r--r--drivers/rtc/rtc-sun6i.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
index 305c4d043f61..3d2216ccd860 100644
--- a/drivers/rtc/rtc-sun6i.c
+++ b/drivers/rtc/rtc-sun6i.c
@@ -73,6 +73,9 @@
#define SUN6I_ALARM_CONFIG 0x0050
#define SUN6I_ALARM_CONFIG_WAKEUP BIT(0)
+#define SUN6I_LOSC_OUT_GATING 0x0060
+#define SUN6I_LOSC_OUT_GATING_EN BIT(0)
+
/*
* Get date values
*/
@@ -125,6 +128,7 @@ struct sun6i_rtc_dev {
struct clk_hw hw;
struct clk_hw *int_osc;
struct clk *losc;
+ struct clk *ext_losc;
spinlock_t lock;
};
@@ -188,13 +192,14 @@ static void __init sun6i_rtc_clk_init(struct device_node *node)
struct clk_init_data init = {
.ops = &sun6i_rtc_osc_ops,
};
+ const char *clkout_name = "osc32k-out";
const char *parents[2];
rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return;
- clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws),
+ clk_data = kzalloc(sizeof(*clk_data) + (sizeof(*clk_data->hws) * 2),
GFP_KERNEL);
if (!clk_data)
return;
@@ -235,7 +240,8 @@ static void __init sun6i_rtc_clk_init(struct device_node *node)
init.parent_names = parents;
init.num_parents = of_clk_get_parent_count(node) + 1;
- of_property_read_string(node, "clock-output-names", &init.name);
+ of_property_read_string_index(node, "clock-output-names", 0,
+ &init.name);
rtc->losc = clk_register(NULL, &rtc->hw);
if (IS_ERR(rtc->losc)) {
@@ -243,8 +249,20 @@ static void __init sun6i_rtc_clk_init(struct device_node *node)
return;
}
- clk_data->num = 1;
+ of_property_read_string_index(node, "clock-output-names", 1,
+ &clkout_name);
+ rtc->ext_losc = clk_register_gate(NULL, clkout_name, rtc->hw.init->name,
+ 0, rtc->base + SUN6I_LOSC_OUT_GATING,
+ SUN6I_LOSC_OUT_GATING_EN, 0,
+ &rtc->lock);
+ if (IS_ERR(rtc->ext_losc)) {
+ pr_crit("Couldn't register the LOSC external gate\n");
+ return;
+ }
+
+ clk_data->num = 2;
clk_data->hws[0] = &rtc->hw;
+ clk_data->hws[1] = __clk_get_hw(rtc->ext_losc);
of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
return;