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>

authored by

Maxime Ripard and committed by
Alexandre Belloni
17ecd246 f22d9cdc

+23 -5
+2 -2
Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
··· 10 11 Required properties for new device trees 12 - clocks : phandle to the 32kHz external oscillator 13 - - clock-output-names : name of the LOSC clock created 14 - #clock-cells : must be equals to 1. The RTC provides two clocks: the 15 LOSC and its external output, with index 0 and 1 16 respectively. ··· 21 compatible = "allwinner,sun6i-a31-rtc"; 22 reg = <0x01f00000 0x54>; 23 interrupts = <0 40 4>, <0 41 4>; 24 - clock-output-names = "osc32k"; 25 clocks = <&ext_osc32k>; 26 #clock-cells = <1>; 27 };
··· 10 11 Required properties for new device trees 12 - clocks : phandle to the 32kHz external oscillator 13 + - clock-output-names : names of the LOSC and its external output clocks created 14 - #clock-cells : must be equals to 1. The RTC provides two clocks: the 15 LOSC and its external output, with index 0 and 1 16 respectively. ··· 21 compatible = "allwinner,sun6i-a31-rtc"; 22 reg = <0x01f00000 0x54>; 23 interrupts = <0 40 4>, <0 41 4>; 24 + clock-output-names = "osc32k", "osc32k-out"; 25 clocks = <&ext_osc32k>; 26 #clock-cells = <1>; 27 };
+21 -3
drivers/rtc/rtc-sun6i.c
··· 73 #define SUN6I_ALARM_CONFIG 0x0050 74 #define SUN6I_ALARM_CONFIG_WAKEUP BIT(0) 75 76 /* 77 * Get date values 78 */ ··· 128 struct clk_hw hw; 129 struct clk_hw *int_osc; 130 struct clk *losc; 131 132 spinlock_t lock; 133 }; ··· 192 struct clk_init_data init = { 193 .ops = &sun6i_rtc_osc_ops, 194 }; 195 const char *parents[2]; 196 197 rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); 198 if (!rtc) 199 return; 200 201 - clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws), 202 GFP_KERNEL); 203 if (!clk_data) 204 return; ··· 240 241 init.parent_names = parents; 242 init.num_parents = of_clk_get_parent_count(node) + 1; 243 - of_property_read_string(node, "clock-output-names", &init.name); 244 245 rtc->losc = clk_register(NULL, &rtc->hw); 246 if (IS_ERR(rtc->losc)) { ··· 249 return; 250 } 251 252 - clk_data->num = 1; 253 clk_data->hws[0] = &rtc->hw; 254 of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); 255 return; 256
··· 73 #define SUN6I_ALARM_CONFIG 0x0050 74 #define SUN6I_ALARM_CONFIG_WAKEUP BIT(0) 75 76 + #define SUN6I_LOSC_OUT_GATING 0x0060 77 + #define SUN6I_LOSC_OUT_GATING_EN BIT(0) 78 + 79 /* 80 * Get date values 81 */ ··· 125 struct clk_hw hw; 126 struct clk_hw *int_osc; 127 struct clk *losc; 128 + struct clk *ext_losc; 129 130 spinlock_t lock; 131 }; ··· 188 struct clk_init_data init = { 189 .ops = &sun6i_rtc_osc_ops, 190 }; 191 + const char *clkout_name = "osc32k-out"; 192 const char *parents[2]; 193 194 rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); 195 if (!rtc) 196 return; 197 198 + clk_data = kzalloc(sizeof(*clk_data) + (sizeof(*clk_data->hws) * 2), 199 GFP_KERNEL); 200 if (!clk_data) 201 return; ··· 235 236 init.parent_names = parents; 237 init.num_parents = of_clk_get_parent_count(node) + 1; 238 + of_property_read_string_index(node, "clock-output-names", 0, 239 + &init.name); 240 241 rtc->losc = clk_register(NULL, &rtc->hw); 242 if (IS_ERR(rtc->losc)) { ··· 243 return; 244 } 245 246 + of_property_read_string_index(node, "clock-output-names", 1, 247 + &clkout_name); 248 + rtc->ext_losc = clk_register_gate(NULL, clkout_name, rtc->hw.init->name, 249 + 0, rtc->base + SUN6I_LOSC_OUT_GATING, 250 + SUN6I_LOSC_OUT_GATING_EN, 0, 251 + &rtc->lock); 252 + if (IS_ERR(rtc->ext_losc)) { 253 + pr_crit("Couldn't register the LOSC external gate\n"); 254 + return; 255 + } 256 + 257 + clk_data->num = 2; 258 clk_data->hws[0] = &rtc->hw; 259 + clk_data->hws[1] = __clk_get_hw(rtc->ext_losc); 260 of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); 261 return; 262