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