1 // SPDX-License-Identifier: GPL-2.0+
3 // clk-max77686.c - Clock driver for Maxim 77686/MAX77802
5 // Copyright (C) 2012 Samsung Electornics
6 // Jonghwa Lee <jonghwa3.lee@samsung.com>
8 #include <linux/kernel.h>
9 #include <linux/slab.h>
10 #include <linux/err.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/mfd/max77620.h>
14 #include <linux/mfd/max77686.h>
15 #include <linux/mfd/max77686-private.h>
16 #include <linux/clk-provider.h>
17 #include <linux/mutex.h>
18 #include <linux/clkdev.h>
20 #include <linux/regmap.h>
22 #include <dt-bindings/clock/maxim,max77686.h>
23 #include <dt-bindings/clock/maxim,max77802.h>
24 #include <dt-bindings/clock/maxim,max77620.h>
26 #define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
28 enum max77686_chip_name
{
34 struct max77686_hw_clk_info
{
41 struct max77686_clk_init_data
{
42 struct regmap
*regmap
;
44 struct clk_init_data clk_idata
;
45 const struct max77686_hw_clk_info
*clk_info
;
48 struct max77686_clk_driver_data
{
49 enum max77686_chip_name chip
;
50 struct max77686_clk_init_data
*max_clk_data
;
55 max77686_hw_clk_info max77686_hw_clks_info
[MAX77686_CLKS_NUM
] = {
58 .clk_reg
= MAX77686_REG_32KHZ
,
59 .clk_enable_mask
= BIT(MAX77686_CLK_AP
),
63 .clk_reg
= MAX77686_REG_32KHZ
,
64 .clk_enable_mask
= BIT(MAX77686_CLK_CP
),
66 [MAX77686_CLK_PMIC
] = {
68 .clk_reg
= MAX77686_REG_32KHZ
,
69 .clk_enable_mask
= BIT(MAX77686_CLK_PMIC
),
74 max77686_hw_clk_info max77802_hw_clks_info
[MAX77802_CLKS_NUM
] = {
75 [MAX77802_CLK_32K_AP
] = {
77 .clk_reg
= MAX77802_REG_32KHZ
,
78 .clk_enable_mask
= BIT(MAX77802_CLK_32K_AP
),
80 [MAX77802_CLK_32K_CP
] = {
82 .clk_reg
= MAX77802_REG_32KHZ
,
83 .clk_enable_mask
= BIT(MAX77802_CLK_32K_CP
),
88 max77686_hw_clk_info max77620_hw_clks_info
[MAX77620_CLKS_NUM
] = {
89 [MAX77620_CLK_32K_OUT0
] = {
91 .clk_reg
= MAX77620_REG_CNFG1_32K
,
92 .clk_enable_mask
= MAX77620_CNFG1_32K_OUT0_EN
,
96 static struct max77686_clk_init_data
*to_max77686_clk_init_data(
99 return container_of(hw
, struct max77686_clk_init_data
, hw
);
102 static int max77686_clk_prepare(struct clk_hw
*hw
)
104 struct max77686_clk_init_data
*max77686
= to_max77686_clk_init_data(hw
);
106 return regmap_update_bits(max77686
->regmap
, max77686
->clk_info
->clk_reg
,
107 max77686
->clk_info
->clk_enable_mask
,
108 max77686
->clk_info
->clk_enable_mask
);
111 static void max77686_clk_unprepare(struct clk_hw
*hw
)
113 struct max77686_clk_init_data
*max77686
= to_max77686_clk_init_data(hw
);
115 regmap_update_bits(max77686
->regmap
, max77686
->clk_info
->clk_reg
,
116 max77686
->clk_info
->clk_enable_mask
,
117 ~max77686
->clk_info
->clk_enable_mask
);
120 static int max77686_clk_is_prepared(struct clk_hw
*hw
)
122 struct max77686_clk_init_data
*max77686
= to_max77686_clk_init_data(hw
);
126 ret
= regmap_read(max77686
->regmap
, max77686
->clk_info
->clk_reg
, &val
);
131 return val
& max77686
->clk_info
->clk_enable_mask
;
134 static unsigned long max77686_recalc_rate(struct clk_hw
*hw
,
135 unsigned long parent_rate
)
140 static const struct clk_ops max77686_clk_ops
= {
141 .prepare
= max77686_clk_prepare
,
142 .unprepare
= max77686_clk_unprepare
,
143 .is_prepared
= max77686_clk_is_prepared
,
144 .recalc_rate
= max77686_recalc_rate
,
147 static struct clk_hw
*
148 of_clk_max77686_get(struct of_phandle_args
*clkspec
, void *data
)
150 struct max77686_clk_driver_data
*drv_data
= data
;
151 unsigned int idx
= clkspec
->args
[0];
153 if (idx
>= drv_data
->num_clks
) {
154 pr_err("%s: invalid index %u\n", __func__
, idx
);
155 return ERR_PTR(-EINVAL
);
158 return &drv_data
->max_clk_data
[idx
].hw
;
161 static int max77686_clk_probe(struct platform_device
*pdev
)
163 struct device
*dev
= &pdev
->dev
;
164 struct device
*parent
= dev
->parent
;
165 const struct platform_device_id
*id
= platform_get_device_id(pdev
);
166 struct max77686_clk_driver_data
*drv_data
;
167 const struct max77686_hw_clk_info
*hw_clks
;
168 struct regmap
*regmap
;
169 int i
, ret
, num_clks
;
171 drv_data
= devm_kzalloc(dev
, sizeof(*drv_data
), GFP_KERNEL
);
175 regmap
= dev_get_regmap(parent
, NULL
);
177 dev_err(dev
, "Failed to get rtc regmap\n");
181 drv_data
->chip
= id
->driver_data
;
183 switch (drv_data
->chip
) {
185 num_clks
= MAX77686_CLKS_NUM
;
186 hw_clks
= max77686_hw_clks_info
;
190 num_clks
= MAX77802_CLKS_NUM
;
191 hw_clks
= max77802_hw_clks_info
;
195 num_clks
= MAX77620_CLKS_NUM
;
196 hw_clks
= max77620_hw_clks_info
;
200 dev_err(dev
, "Unknown Chip ID\n");
204 drv_data
->num_clks
= num_clks
;
205 drv_data
->max_clk_data
= devm_kcalloc(dev
, num_clks
,
206 sizeof(*drv_data
->max_clk_data
),
208 if (!drv_data
->max_clk_data
)
211 for (i
= 0; i
< num_clks
; i
++) {
212 struct max77686_clk_init_data
*max_clk_data
;
213 const char *clk_name
;
215 max_clk_data
= &drv_data
->max_clk_data
[i
];
217 max_clk_data
->regmap
= regmap
;
218 max_clk_data
->clk_info
= &hw_clks
[i
];
219 max_clk_data
->clk_idata
.flags
= hw_clks
[i
].flags
;
220 max_clk_data
->clk_idata
.ops
= &max77686_clk_ops
;
222 if (parent
->of_node
&&
223 !of_property_read_string_index(parent
->of_node
,
224 "clock-output-names",
226 max_clk_data
->clk_idata
.name
= clk_name
;
228 max_clk_data
->clk_idata
.name
= hw_clks
[i
].name
;
230 max_clk_data
->hw
.init
= &max_clk_data
->clk_idata
;
232 ret
= devm_clk_hw_register(dev
, &max_clk_data
->hw
);
234 dev_err(dev
, "Failed to clock register: %d\n", ret
);
238 ret
= devm_clk_hw_register_clkdev(dev
, &max_clk_data
->hw
,
239 max_clk_data
->clk_idata
.name
,
242 dev_err(dev
, "Failed to clkdev register: %d\n", ret
);
247 if (parent
->of_node
) {
248 ret
= devm_of_clk_add_hw_provider(dev
, of_clk_max77686_get
,
252 dev_err(dev
, "Failed to register OF clock provider: %d\n",
258 /* MAX77802: Enable low-jitter mode on the 32khz clocks. */
259 if (drv_data
->chip
== CHIP_MAX77802
) {
260 ret
= regmap_update_bits(regmap
, MAX77802_REG_32KHZ
,
261 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT
,
262 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT
);
264 dev_err(dev
, "Failed to config low-jitter: %d\n", ret
);
272 static const struct platform_device_id max77686_clk_id
[] = {
273 { "max77686-clk", .driver_data
= CHIP_MAX77686
, },
274 { "max77802-clk", .driver_data
= CHIP_MAX77802
, },
275 { "max77620-clock", .driver_data
= CHIP_MAX77620
, },
278 MODULE_DEVICE_TABLE(platform
, max77686_clk_id
);
280 static struct platform_driver max77686_clk_driver
= {
282 .name
= "max77686-clk",
284 .probe
= max77686_clk_probe
,
285 .id_table
= max77686_clk_id
,
288 module_platform_driver(max77686_clk_driver
);
290 MODULE_DESCRIPTION("MAXIM 77686 Clock Driver");
291 MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
292 MODULE_LICENSE("GPL");