2 * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks
4 * Copyright (C) 2014 Google, Inc
6 * Copyright (C) 2012 Samsung Electornics
7 * Jonghwa Lee <jonghwa3.lee@samsung.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * This driver is based on clk-max77686.c
23 #include <linux/kernel.h>
24 #include <linux/slab.h>
25 #include <linux/err.h>
26 #include <linux/regmap.h>
27 #include <linux/platform_device.h>
28 #include <linux/clk-provider.h>
29 #include <linux/mutex.h>
30 #include <linux/clkdev.h>
32 #include <linux/export.h>
35 struct regmap
*regmap
;
41 static struct max_gen_clk
*to_max_gen_clk(struct clk_hw
*hw
)
43 return container_of(hw
, struct max_gen_clk
, hw
);
46 static int max_gen_clk_prepare(struct clk_hw
*hw
)
48 struct max_gen_clk
*max_gen
= to_max_gen_clk(hw
);
50 return regmap_update_bits(max_gen
->regmap
, max_gen
->reg
,
51 max_gen
->mask
, max_gen
->mask
);
54 static void max_gen_clk_unprepare(struct clk_hw
*hw
)
56 struct max_gen_clk
*max_gen
= to_max_gen_clk(hw
);
58 regmap_update_bits(max_gen
->regmap
, max_gen
->reg
,
59 max_gen
->mask
, ~max_gen
->mask
);
62 static int max_gen_clk_is_prepared(struct clk_hw
*hw
)
64 struct max_gen_clk
*max_gen
= to_max_gen_clk(hw
);
68 ret
= regmap_read(max_gen
->regmap
, max_gen
->reg
, &val
);
73 return val
& max_gen
->mask
;
76 static unsigned long max_gen_recalc_rate(struct clk_hw
*hw
,
77 unsigned long parent_rate
)
82 struct clk_ops max_gen_clk_ops
= {
83 .prepare
= max_gen_clk_prepare
,
84 .unprepare
= max_gen_clk_unprepare
,
85 .is_prepared
= max_gen_clk_is_prepared
,
86 .recalc_rate
= max_gen_recalc_rate
,
88 EXPORT_SYMBOL_GPL(max_gen_clk_ops
);
90 static struct clk
*max_gen_clk_register(struct device
*dev
,
91 struct max_gen_clk
*max_gen
)
94 struct clk_hw
*hw
= &max_gen
->hw
;
97 clk
= devm_clk_register(dev
, hw
);
101 ret
= clk_register_clkdev(clk
, hw
->init
->name
, NULL
);
109 int max_gen_clk_probe(struct platform_device
*pdev
, struct regmap
*regmap
,
110 u32 reg
, struct clk_init_data
*clks_init
, int num_init
)
113 struct max_gen_clk
*max_gen_clks
;
115 struct device
*dev
= pdev
->dev
.parent
;
116 const char *clk_name
;
117 struct clk_init_data
*init
;
119 clocks
= devm_kzalloc(dev
, sizeof(struct clk
*) * num_init
, GFP_KERNEL
);
123 max_gen_clks
= devm_kzalloc(dev
, sizeof(struct max_gen_clk
)
124 * num_init
, GFP_KERNEL
);
128 for (i
= 0; i
< num_init
; i
++) {
129 max_gen_clks
[i
].regmap
= regmap
;
130 max_gen_clks
[i
].mask
= 1 << i
;
131 max_gen_clks
[i
].reg
= reg
;
133 init
= devm_kzalloc(dev
, sizeof(*init
), GFP_KERNEL
);
138 !of_property_read_string_index(dev
->of_node
,
139 "clock-output-names",
141 init
->name
= clk_name
;
143 init
->name
= clks_init
[i
].name
;
145 init
->ops
= clks_init
[i
].ops
;
146 init
->flags
= clks_init
[i
].flags
;
148 max_gen_clks
[i
].hw
.init
= init
;
150 clocks
[i
] = max_gen_clk_register(dev
, &max_gen_clks
[i
]);
151 if (IS_ERR(clocks
[i
])) {
152 ret
= PTR_ERR(clocks
[i
]);
153 dev_err(dev
, "failed to register %s\n",
154 max_gen_clks
[i
].hw
.init
->name
);
159 platform_set_drvdata(pdev
, clocks
);
162 struct clk_onecell_data
*of_data
;
164 of_data
= devm_kzalloc(dev
, sizeof(*of_data
), GFP_KERNEL
);
168 of_data
->clks
= clocks
;
169 of_data
->clk_num
= num_init
;
170 ret
= of_clk_add_provider(dev
->of_node
, of_clk_src_onecell_get
,
174 dev_err(dev
, "failed to register OF clock provider\n");
181 EXPORT_SYMBOL_GPL(max_gen_clk_probe
);
183 int max_gen_clk_remove(struct platform_device
*pdev
, int num_init
)
185 struct device
*dev
= pdev
->dev
.parent
;
188 of_clk_del_provider(dev
->of_node
);
192 EXPORT_SYMBOL_GPL(max_gen_clk_remove
);