drm/tests: hdmi: Fix memory leaks in drm_display_mode_from_cea_vic()
[drm/drm-misc.git] / drivers / clk / clk-twl.c
blobeab9d3c8ed8aee9211a18c40c33b539ee19c746b
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Clock driver for twl device.
5 * inspired by the driver for the Palmas device
6 */
8 #include <linux/clk-provider.h>
9 #include <linux/mfd/twl.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/slab.h>
14 #define VREG_STATE 2
15 #define TWL6030_CFG_STATE_OFF 0x00
16 #define TWL6030_CFG_STATE_ON 0x01
17 #define TWL6030_CFG_STATE_MASK 0x03
19 struct twl_clock_info {
20 struct device *dev;
21 u8 base;
22 struct clk_hw hw;
25 static inline int
26 twlclk_read(struct twl_clock_info *info, unsigned int slave_subgp,
27 unsigned int offset)
29 u8 value;
30 int status;
32 status = twl_i2c_read_u8(slave_subgp, &value,
33 info->base + offset);
34 return (status < 0) ? status : value;
37 static inline int
38 twlclk_write(struct twl_clock_info *info, unsigned int slave_subgp,
39 unsigned int offset, u8 value)
41 return twl_i2c_write_u8(slave_subgp, value,
42 info->base + offset);
45 static inline struct twl_clock_info *to_twl_clks_info(struct clk_hw *hw)
47 return container_of(hw, struct twl_clock_info, hw);
50 static unsigned long twl_clks_recalc_rate(struct clk_hw *hw,
51 unsigned long parent_rate)
53 return 32768;
56 static int twl6032_clks_prepare(struct clk_hw *hw)
58 struct twl_clock_info *cinfo = to_twl_clks_info(hw);
59 int ret;
61 ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
62 TWL6030_CFG_STATE_ON);
63 if (ret < 0)
64 dev_err(cinfo->dev, "clk prepare failed\n");
66 return ret;
69 static void twl6032_clks_unprepare(struct clk_hw *hw)
71 struct twl_clock_info *cinfo = to_twl_clks_info(hw);
72 int ret;
74 ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
75 TWL6030_CFG_STATE_OFF);
76 if (ret < 0)
77 dev_err(cinfo->dev, "clk unprepare failed\n");
80 static int twl6032_clks_is_prepared(struct clk_hw *hw)
82 struct twl_clock_info *cinfo = to_twl_clks_info(hw);
83 int val;
85 val = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE);
86 if (val < 0) {
87 dev_err(cinfo->dev, "clk read failed\n");
88 return val;
91 val &= TWL6030_CFG_STATE_MASK;
93 return val == TWL6030_CFG_STATE_ON;
96 static const struct clk_ops twl6032_clks_ops = {
97 .prepare = twl6032_clks_prepare,
98 .unprepare = twl6032_clks_unprepare,
99 .is_prepared = twl6032_clks_is_prepared,
100 .recalc_rate = twl_clks_recalc_rate,
103 struct twl_clks_data {
104 struct clk_init_data init;
105 u8 base;
108 static const struct twl_clks_data twl6032_clks[] = {
110 .init = {
111 .name = "clk32kg",
112 .ops = &twl6032_clks_ops,
113 .flags = CLK_IGNORE_UNUSED,
115 .base = 0x8C,
118 .init = {
119 .name = "clk32kaudio",
120 .ops = &twl6032_clks_ops,
121 .flags = CLK_IGNORE_UNUSED,
123 .base = 0x8F,
126 /* sentinel */
130 static int twl_clks_probe(struct platform_device *pdev)
132 struct clk_hw_onecell_data *clk_data;
133 const struct twl_clks_data *hw_data;
135 struct twl_clock_info *cinfo;
136 int ret;
137 int i;
138 int count;
140 hw_data = twl6032_clks;
141 for (count = 0; hw_data[count].init.name; count++)
144 clk_data = devm_kzalloc(&pdev->dev,
145 struct_size(clk_data, hws, count),
146 GFP_KERNEL);
147 if (!clk_data)
148 return -ENOMEM;
150 clk_data->num = count;
151 cinfo = devm_kcalloc(&pdev->dev, count, sizeof(*cinfo), GFP_KERNEL);
152 if (!cinfo)
153 return -ENOMEM;
155 for (i = 0; i < count; i++) {
156 cinfo[i].base = hw_data[i].base;
157 cinfo[i].dev = &pdev->dev;
158 cinfo[i].hw.init = &hw_data[i].init;
159 ret = devm_clk_hw_register(&pdev->dev, &cinfo[i].hw);
160 if (ret) {
161 return dev_err_probe(&pdev->dev, ret,
162 "Fail to register clock %s\n",
163 hw_data[i].init.name);
165 clk_data->hws[i] = &cinfo[i].hw;
168 ret = devm_of_clk_add_hw_provider(&pdev->dev,
169 of_clk_hw_onecell_get, clk_data);
170 if (ret < 0)
171 return dev_err_probe(&pdev->dev, ret,
172 "Fail to add clock driver\n");
174 return 0;
177 static const struct platform_device_id twl_clks_id[] = {
179 .name = "twl6032-clk",
180 }, {
181 /* sentinel */
184 MODULE_DEVICE_TABLE(platform, twl_clks_id);
186 static struct platform_driver twl_clks_driver = {
187 .driver = {
188 .name = "twl-clk",
190 .probe = twl_clks_probe,
191 .id_table = twl_clks_id,
194 module_platform_driver(twl_clks_driver);
196 MODULE_DESCRIPTION("Clock driver for TWL Series Devices");
197 MODULE_LICENSE("GPL");