Skip to content

Commit 5ddfa14

Browse files
pcercueialexandrebelloni
authored andcommitted
rtc: jz4740: Register clock provider for the CLK32K pin
On JZ4770 and JZ4780, the CLK32K pin is configurable. By default, it is configured as a GPIO in input mode, and its value can be read through GPIO PD14. With this change, clients can now request the 32 kHz clock on the CLK32K pin, through Device Tree. This clock is simply a pass-through of the input oscillator's clock with enable/disable operations. This will permit the WiFi/Bluetooth chip to work on the MIPS CI20 board, which does source one of its clocks from the CLK32K pin. Signed-off-by: Paul Cercueil <paul@crapouillou.net> Link: https://lore.kernel.org/r/20230129120442.22858-5-paul@crapouillou.net Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent ff6fd37 commit 5ddfa14

2 files changed

Lines changed: 57 additions & 1 deletion

File tree

drivers/rtc/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1690,7 +1690,7 @@ config RTC_DRV_MPC5121
16901690
config RTC_DRV_JZ4740
16911691
tristate "Ingenic JZ4740 SoC"
16921692
depends on MIPS || COMPILE_TEST
1693-
depends on OF
1693+
depends on OF && COMMON_CLK
16941694
help
16951695
If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
16961696
controllers.

drivers/rtc/rtc-jz4740.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
*/
77

88
#include <linux/clk.h>
9+
#include <linux/clk-provider.h>
910
#include <linux/io.h>
1011
#include <linux/iopoll.h>
1112
#include <linux/kernel.h>
1213
#include <linux/module.h>
1314
#include <linux/of_device.h>
1415
#include <linux/platform_device.h>
1516
#include <linux/pm_wakeirq.h>
17+
#include <linux/property.h>
1618
#include <linux/reboot.h>
1719
#include <linux/rtc.h>
1820
#include <linux/slab.h>
@@ -26,6 +28,7 @@
2628
#define JZ_REG_RTC_WAKEUP_FILTER 0x24
2729
#define JZ_REG_RTC_RESET_COUNTER 0x28
2830
#define JZ_REG_RTC_SCRATCHPAD 0x34
31+
#define JZ_REG_RTC_CKPCR 0x40
2932

3033
/* The following are present on the jz4780 */
3134
#define JZ_REG_RTC_WENR 0x3C
@@ -45,6 +48,9 @@
4548
#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0
4649
#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0
4750

51+
#define JZ_RTC_CKPCR_CK32PULL_DIS BIT(4)
52+
#define JZ_RTC_CKPCR_CK32CTL_EN (BIT(2) | BIT(1))
53+
4854
enum jz4740_rtc_type {
4955
ID_JZ4740,
5056
ID_JZ4760,
@@ -57,6 +63,8 @@ struct jz4740_rtc {
5763

5864
struct rtc_device *rtc;
5965

66+
struct clk_hw clk32k;
67+
6068
spinlock_t lock;
6169
};
6270

@@ -254,6 +262,7 @@ static void jz4740_rtc_power_off(void)
254262
static const struct of_device_id jz4740_rtc_of_match[] = {
255263
{ .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 },
256264
{ .compatible = "ingenic,jz4760-rtc", .data = (void *)ID_JZ4760 },
265+
{ .compatible = "ingenic,jz4770-rtc", .data = (void *)ID_JZ4780 },
257266
{ .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 },
258267
{},
259268
};
@@ -295,6 +304,38 @@ static void jz4740_rtc_set_wakeup_params(struct jz4740_rtc *rtc,
295304
jz4740_rtc_reg_write(rtc, JZ_REG_RTC_RESET_COUNTER, reset_ticks);
296305
}
297306

307+
static int jz4740_rtc_clk32k_enable(struct clk_hw *hw)
308+
{
309+
struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
310+
311+
return jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CKPCR,
312+
JZ_RTC_CKPCR_CK32PULL_DIS |
313+
JZ_RTC_CKPCR_CK32CTL_EN);
314+
}
315+
316+
static void jz4740_rtc_clk32k_disable(struct clk_hw *hw)
317+
{
318+
struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
319+
320+
jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CKPCR, 0);
321+
}
322+
323+
static int jz4740_rtc_clk32k_is_enabled(struct clk_hw *hw)
324+
{
325+
struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
326+
u32 ckpcr;
327+
328+
ckpcr = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CKPCR);
329+
330+
return !!(ckpcr & JZ_RTC_CKPCR_CK32CTL_EN);
331+
}
332+
333+
static const struct clk_ops jz4740_rtc_clk32k_ops = {
334+
.enable = jz4740_rtc_clk32k_enable,
335+
.disable = jz4740_rtc_clk32k_disable,
336+
.is_enabled = jz4740_rtc_clk32k_is_enabled,
337+
};
338+
298339
static int jz4740_rtc_probe(struct platform_device *pdev)
299340
{
300341
struct device *dev = &pdev->dev;
@@ -364,6 +405,21 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
364405
dev_warn(dev, "Poweroff handler already present!\n");
365406
}
366407

408+
if (device_property_present(dev, "#clock-cells")) {
409+
rtc->clk32k.init = CLK_HW_INIT_HW("clk32k", __clk_get_hw(clk),
410+
&jz4740_rtc_clk32k_ops, 0);
411+
412+
ret = devm_clk_hw_register(dev, &rtc->clk32k);
413+
if (ret)
414+
return dev_err_probe(dev, ret,
415+
"Unable to register clk32k clock\n");
416+
417+
ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &rtc->clk32k);
418+
if (ret)
419+
return dev_err_probe(dev, ret,
420+
"Unable to register clk32k clock provider\n");
421+
}
422+
367423
return 0;
368424
}
369425

0 commit comments

Comments
 (0)