xref: /OK3568_Linux_fs/kernel/drivers/mfd/rk618.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2017 Rockchip Electronics Co. Ltd.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
5*4882a593Smuzhiyun  * it under the terms of the GNU General Public License as published by
6*4882a593Smuzhiyun  * the Free Software Foundation; either version 2 of the License, or
7*4882a593Smuzhiyun  * (at your option) any later version.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful,
10*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*4882a593Smuzhiyun  * GNU General Public License for more details.
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/init.h>
17*4882a593Smuzhiyun #include <linux/i2c.h>
18*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
19*4882a593Smuzhiyun #include <linux/pinctrl/consumer.h>
20*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
21*4882a593Smuzhiyun #include <linux/mfd/core.h>
22*4882a593Smuzhiyun #include <linux/mfd/rk618.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun static const struct mfd_cell rk618_devs[] = {
25*4882a593Smuzhiyun 	{
26*4882a593Smuzhiyun 		.name = "rk618-codec",
27*4882a593Smuzhiyun 		.of_compatible = "rockchip,rk618-codec",
28*4882a593Smuzhiyun 	}, {
29*4882a593Smuzhiyun 		.name = "rk618-cru",
30*4882a593Smuzhiyun 		.of_compatible = "rockchip,rk618-cru",
31*4882a593Smuzhiyun 	}, {
32*4882a593Smuzhiyun 		.name = "rk618-dsi",
33*4882a593Smuzhiyun 		.of_compatible = "rockchip,rk618-dsi",
34*4882a593Smuzhiyun 	}, {
35*4882a593Smuzhiyun 		.name = "rk618-hdmi",
36*4882a593Smuzhiyun 		.of_compatible = "rockchip,rk618-hdmi",
37*4882a593Smuzhiyun 	}, {
38*4882a593Smuzhiyun 		.name = "rk618-lvds",
39*4882a593Smuzhiyun 		.of_compatible = "rockchip,rk618-lvds",
40*4882a593Smuzhiyun 	}, {
41*4882a593Smuzhiyun 		.name = "rk618-rgb",
42*4882a593Smuzhiyun 		.of_compatible = "rockchip,rk618-rgb",
43*4882a593Smuzhiyun 	}, {
44*4882a593Smuzhiyun 		.name = "rk618-scaler",
45*4882a593Smuzhiyun 		.of_compatible = "rockchip,rk618-scaler",
46*4882a593Smuzhiyun 	}, {
47*4882a593Smuzhiyun 		.name = "rk618-vif",
48*4882a593Smuzhiyun 		.of_compatible = "rockchip,rk618-vif",
49*4882a593Smuzhiyun 	},
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
rk618_power_on(struct rk618 * rk618)52*4882a593Smuzhiyun static int rk618_power_on(struct rk618 *rk618)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	u32 reg;
55*4882a593Smuzhiyun 	int ret;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	ret = regulator_enable(rk618->supply);
58*4882a593Smuzhiyun 	if (ret < 0) {
59*4882a593Smuzhiyun 		dev_err(rk618->dev, "failed to enable supply: %d\n", ret);
60*4882a593Smuzhiyun 		return ret;
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (rk618->enable_gpio)
64*4882a593Smuzhiyun 		gpiod_direction_output(rk618->enable_gpio, 1);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	usleep_range(1000, 2000);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	ret = regmap_read(rk618->regmap, 0x0000, &reg);
69*4882a593Smuzhiyun 	if (ret) {
70*4882a593Smuzhiyun 		gpiod_direction_output(rk618->reset_gpio, 0);
71*4882a593Smuzhiyun 		usleep_range(2000, 4000);
72*4882a593Smuzhiyun 		gpiod_direction_output(rk618->reset_gpio, 1);
73*4882a593Smuzhiyun 		usleep_range(50000, 60000);
74*4882a593Smuzhiyun 		gpiod_direction_output(rk618->reset_gpio, 0);
75*4882a593Smuzhiyun 	}
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	return 0;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
rk618_power_off(struct rk618 * rk618)80*4882a593Smuzhiyun static void rk618_power_off(struct rk618 *rk618)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	gpiod_direction_output(rk618->reset_gpio, 1);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (rk618->enable_gpio)
85*4882a593Smuzhiyun 		gpiod_direction_output(rk618->enable_gpio, 0);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	regulator_disable(rk618->supply);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun static const struct regmap_config rk618_regmap_config = {
91*4882a593Smuzhiyun 	.name = "core",
92*4882a593Smuzhiyun 	.reg_bits = 16,
93*4882a593Smuzhiyun 	.val_bits = 32,
94*4882a593Smuzhiyun 	.reg_stride = 4,
95*4882a593Smuzhiyun 	.max_register = 0x9c,
96*4882a593Smuzhiyun 	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
97*4882a593Smuzhiyun 	.val_format_endian = REGMAP_ENDIAN_NATIVE,
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun static int
rk618_probe(struct i2c_client * client,const struct i2c_device_id * id)101*4882a593Smuzhiyun rk618_probe(struct i2c_client *client, const struct i2c_device_id *id)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	struct device *dev = &client->dev;
104*4882a593Smuzhiyun 	struct rk618 *rk618;
105*4882a593Smuzhiyun 	int ret;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	rk618 = devm_kzalloc(dev, sizeof(*rk618), GFP_KERNEL);
108*4882a593Smuzhiyun 	if (!rk618)
109*4882a593Smuzhiyun 		return -ENOMEM;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	rk618->dev = dev;
112*4882a593Smuzhiyun 	rk618->client = client;
113*4882a593Smuzhiyun 	i2c_set_clientdata(client, rk618);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	rk618->supply = devm_regulator_get(dev, "power");
116*4882a593Smuzhiyun 	if (IS_ERR(rk618->supply))
117*4882a593Smuzhiyun 		return PTR_ERR(rk618->supply);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	rk618->enable_gpio = devm_gpiod_get_optional(dev, "enable", 0);
120*4882a593Smuzhiyun 	if (IS_ERR(rk618->enable_gpio)) {
121*4882a593Smuzhiyun 		ret = PTR_ERR(rk618->enable_gpio);
122*4882a593Smuzhiyun 		dev_err(dev, "failed to request enable GPIO: %d\n", ret);
123*4882a593Smuzhiyun 		return ret;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	rk618->reset_gpio = devm_gpiod_get(dev, "reset", 0);
127*4882a593Smuzhiyun 	if (IS_ERR(rk618->reset_gpio)) {
128*4882a593Smuzhiyun 		ret = PTR_ERR(rk618->reset_gpio);
129*4882a593Smuzhiyun 		dev_err(dev, "failed to request reset GPIO: %d\n", ret);
130*4882a593Smuzhiyun 		return ret;
131*4882a593Smuzhiyun 	}
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	rk618->clkin = devm_clk_get(dev, "clkin");
134*4882a593Smuzhiyun 	if (IS_ERR(rk618->clkin)) {
135*4882a593Smuzhiyun 		dev_err(dev, "failed to get clock\n");
136*4882a593Smuzhiyun 		return PTR_ERR(rk618->clkin);
137*4882a593Smuzhiyun 	}
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	ret = clk_prepare_enable(rk618->clkin);
140*4882a593Smuzhiyun 	if (ret) {
141*4882a593Smuzhiyun 		dev_err(dev, "unable to enable clock: %d\n", ret);
142*4882a593Smuzhiyun 		return ret;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	rk618->regmap = devm_regmap_init_i2c(client, &rk618_regmap_config);
146*4882a593Smuzhiyun 	if (IS_ERR(rk618->regmap)) {
147*4882a593Smuzhiyun 		ret = PTR_ERR(rk618->regmap);
148*4882a593Smuzhiyun 		dev_err(dev, "failed to allocate register map: %d\n", ret);
149*4882a593Smuzhiyun 		goto err_clk_disable;
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	ret = rk618_power_on(rk618);
153*4882a593Smuzhiyun 	if (ret)
154*4882a593Smuzhiyun 		goto err_clk_disable;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	ret = mfd_add_devices(dev, -1, rk618_devs, ARRAY_SIZE(rk618_devs),
157*4882a593Smuzhiyun 			      NULL, 0, NULL);
158*4882a593Smuzhiyun 	if (ret) {
159*4882a593Smuzhiyun 		dev_err(dev, "failed to add subdev: %d\n", ret);
160*4882a593Smuzhiyun 		goto err_clk_disable;
161*4882a593Smuzhiyun 	}
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	return 0;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun err_clk_disable:
166*4882a593Smuzhiyun 	clk_disable_unprepare(rk618->clkin);
167*4882a593Smuzhiyun 	return ret;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
rk618_remove(struct i2c_client * client)170*4882a593Smuzhiyun static int rk618_remove(struct i2c_client *client)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct rk618 *rk618 = i2c_get_clientdata(client);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	mfd_remove_devices(rk618->dev);
175*4882a593Smuzhiyun 	rk618_power_off(rk618);
176*4882a593Smuzhiyun 	clk_disable_unprepare(rk618->clkin);
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	return 0;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
rk618_shutdown(struct i2c_client * client)181*4882a593Smuzhiyun static void rk618_shutdown(struct i2c_client *client)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct rk618 *rk618 = i2c_get_clientdata(client);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	rk618_power_off(rk618);
186*4882a593Smuzhiyun 	clk_disable_unprepare(rk618->clkin);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
rk618_suspend(struct device * dev)189*4882a593Smuzhiyun static int __maybe_unused rk618_suspend(struct device *dev)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	pinctrl_pm_select_sleep_state(dev);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	return 0;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
rk618_resume(struct device * dev)196*4882a593Smuzhiyun static int __maybe_unused rk618_resume(struct device *dev)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	pinctrl_pm_select_default_state(dev);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	return 0;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun static const struct dev_pm_ops rk618_pm_ops = {
204*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(rk618_suspend, rk618_resume)
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun static const struct of_device_id rk618_of_match[] = {
208*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk618", },
209*4882a593Smuzhiyun 	{}
210*4882a593Smuzhiyun };
211*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, rk618_of_match);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun static const struct i2c_device_id rk618_i2c_id[] = {
214*4882a593Smuzhiyun 	{ "rk618", 0 },
215*4882a593Smuzhiyun 	{}
216*4882a593Smuzhiyun };
217*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, rk618_i2c_id);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun static struct i2c_driver rk618_driver = {
220*4882a593Smuzhiyun 	.driver = {
221*4882a593Smuzhiyun 		.name = "rk618",
222*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(rk618_of_match),
223*4882a593Smuzhiyun 		.pm = &rk618_pm_ops,
224*4882a593Smuzhiyun 	},
225*4882a593Smuzhiyun 	.probe = rk618_probe,
226*4882a593Smuzhiyun 	.remove = rk618_remove,
227*4882a593Smuzhiyun 	.shutdown = rk618_shutdown,
228*4882a593Smuzhiyun 	.id_table = rk618_i2c_id,
229*4882a593Smuzhiyun };
230*4882a593Smuzhiyun module_i2c_driver(rk618_driver);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
233*4882a593Smuzhiyun MODULE_DESCRIPTION("Rockchip rk618 i2c driver");
234*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
235