xref: /OK3568_Linux_fs/kernel/drivers/video/fbdev/simplefb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Simplest possible simple frame-buffer driver, as a platform device
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2013, Stephen Warren
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Based on q40fb.c, which was:
8*4882a593Smuzhiyun  * Copyright (C) 2001 Richard Zidlicky <rz@linux-m68k.org>
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Also based on offb.c, which was:
11*4882a593Smuzhiyun  * Copyright (C) 1997 Geert Uytterhoeven
12*4882a593Smuzhiyun  * Copyright (C) 1996 Paul Mackerras
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <linux/errno.h>
16*4882a593Smuzhiyun #include <linux/fb.h>
17*4882a593Smuzhiyun #include <linux/io.h>
18*4882a593Smuzhiyun #include <linux/module.h>
19*4882a593Smuzhiyun #include <linux/platform_data/simplefb.h>
20*4882a593Smuzhiyun #include <linux/platform_device.h>
21*4882a593Smuzhiyun #include <linux/clk.h>
22*4882a593Smuzhiyun #include <linux/of.h>
23*4882a593Smuzhiyun #include <linux/of_clk.h>
24*4882a593Smuzhiyun #include <linux/of_platform.h>
25*4882a593Smuzhiyun #include <linux/parser.h>
26*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun static const struct fb_fix_screeninfo simplefb_fix = {
29*4882a593Smuzhiyun 	.id		= "simple",
30*4882a593Smuzhiyun 	.type		= FB_TYPE_PACKED_PIXELS,
31*4882a593Smuzhiyun 	.visual		= FB_VISUAL_TRUECOLOR,
32*4882a593Smuzhiyun 	.accel		= FB_ACCEL_NONE,
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static const struct fb_var_screeninfo simplefb_var = {
36*4882a593Smuzhiyun 	.height		= -1,
37*4882a593Smuzhiyun 	.width		= -1,
38*4882a593Smuzhiyun 	.activate	= FB_ACTIVATE_NOW,
39*4882a593Smuzhiyun 	.vmode		= FB_VMODE_NONINTERLACED,
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define PSEUDO_PALETTE_SIZE 16
43*4882a593Smuzhiyun 
simplefb_setcolreg(u_int regno,u_int red,u_int green,u_int blue,u_int transp,struct fb_info * info)44*4882a593Smuzhiyun static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
45*4882a593Smuzhiyun 			      u_int transp, struct fb_info *info)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	u32 *pal = info->pseudo_palette;
48*4882a593Smuzhiyun 	u32 cr = red >> (16 - info->var.red.length);
49*4882a593Smuzhiyun 	u32 cg = green >> (16 - info->var.green.length);
50*4882a593Smuzhiyun 	u32 cb = blue >> (16 - info->var.blue.length);
51*4882a593Smuzhiyun 	u32 value;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	if (regno >= PSEUDO_PALETTE_SIZE)
54*4882a593Smuzhiyun 		return -EINVAL;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	value = (cr << info->var.red.offset) |
57*4882a593Smuzhiyun 		(cg << info->var.green.offset) |
58*4882a593Smuzhiyun 		(cb << info->var.blue.offset);
59*4882a593Smuzhiyun 	if (info->var.transp.length > 0) {
60*4882a593Smuzhiyun 		u32 mask = (1 << info->var.transp.length) - 1;
61*4882a593Smuzhiyun 		mask <<= info->var.transp.offset;
62*4882a593Smuzhiyun 		value |= mask;
63*4882a593Smuzhiyun 	}
64*4882a593Smuzhiyun 	pal[regno] = value;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	return 0;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun struct simplefb_par;
70*4882a593Smuzhiyun static void simplefb_clocks_destroy(struct simplefb_par *par);
71*4882a593Smuzhiyun static void simplefb_regulators_destroy(struct simplefb_par *par);
72*4882a593Smuzhiyun 
simplefb_destroy(struct fb_info * info)73*4882a593Smuzhiyun static void simplefb_destroy(struct fb_info *info)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	simplefb_regulators_destroy(info->par);
76*4882a593Smuzhiyun 	simplefb_clocks_destroy(info->par);
77*4882a593Smuzhiyun 	if (info->screen_base)
78*4882a593Smuzhiyun 		iounmap(info->screen_base);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static const struct fb_ops simplefb_ops = {
82*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
83*4882a593Smuzhiyun 	.fb_destroy	= simplefb_destroy,
84*4882a593Smuzhiyun 	.fb_setcolreg	= simplefb_setcolreg,
85*4882a593Smuzhiyun 	.fb_fillrect	= cfb_fillrect,
86*4882a593Smuzhiyun 	.fb_copyarea	= cfb_copyarea,
87*4882a593Smuzhiyun 	.fb_imageblit	= cfb_imageblit,
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun static struct simplefb_format simplefb_formats[] = SIMPLEFB_FORMATS;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun struct simplefb_params {
93*4882a593Smuzhiyun 	u32 width;
94*4882a593Smuzhiyun 	u32 height;
95*4882a593Smuzhiyun 	u32 stride;
96*4882a593Smuzhiyun 	struct simplefb_format *format;
97*4882a593Smuzhiyun };
98*4882a593Smuzhiyun 
simplefb_parse_dt(struct platform_device * pdev,struct simplefb_params * params)99*4882a593Smuzhiyun static int simplefb_parse_dt(struct platform_device *pdev,
100*4882a593Smuzhiyun 			   struct simplefb_params *params)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	struct device_node *np = pdev->dev.of_node;
103*4882a593Smuzhiyun 	int ret;
104*4882a593Smuzhiyun 	const char *format;
105*4882a593Smuzhiyun 	int i;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "width", &params->width);
108*4882a593Smuzhiyun 	if (ret) {
109*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Can't parse width property\n");
110*4882a593Smuzhiyun 		return ret;
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "height", &params->height);
114*4882a593Smuzhiyun 	if (ret) {
115*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Can't parse height property\n");
116*4882a593Smuzhiyun 		return ret;
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "stride", &params->stride);
120*4882a593Smuzhiyun 	if (ret) {
121*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Can't parse stride property\n");
122*4882a593Smuzhiyun 		return ret;
123*4882a593Smuzhiyun 	}
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	ret = of_property_read_string(np, "format", &format);
126*4882a593Smuzhiyun 	if (ret) {
127*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Can't parse format property\n");
128*4882a593Smuzhiyun 		return ret;
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 	params->format = NULL;
131*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
132*4882a593Smuzhiyun 		if (strcmp(format, simplefb_formats[i].name))
133*4882a593Smuzhiyun 			continue;
134*4882a593Smuzhiyun 		params->format = &simplefb_formats[i];
135*4882a593Smuzhiyun 		break;
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 	if (!params->format) {
138*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Invalid format value\n");
139*4882a593Smuzhiyun 		return -EINVAL;
140*4882a593Smuzhiyun 	}
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	return 0;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
simplefb_parse_pd(struct platform_device * pdev,struct simplefb_params * params)145*4882a593Smuzhiyun static int simplefb_parse_pd(struct platform_device *pdev,
146*4882a593Smuzhiyun 			     struct simplefb_params *params)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);
149*4882a593Smuzhiyun 	int i;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	params->width = pd->width;
152*4882a593Smuzhiyun 	params->height = pd->height;
153*4882a593Smuzhiyun 	params->stride = pd->stride;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	params->format = NULL;
156*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
157*4882a593Smuzhiyun 		if (strcmp(pd->format, simplefb_formats[i].name))
158*4882a593Smuzhiyun 			continue;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 		params->format = &simplefb_formats[i];
161*4882a593Smuzhiyun 		break;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (!params->format) {
165*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Invalid format value\n");
166*4882a593Smuzhiyun 		return -EINVAL;
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return 0;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun struct simplefb_par {
173*4882a593Smuzhiyun 	u32 palette[PSEUDO_PALETTE_SIZE];
174*4882a593Smuzhiyun #if defined CONFIG_OF && defined CONFIG_COMMON_CLK
175*4882a593Smuzhiyun 	bool clks_enabled;
176*4882a593Smuzhiyun 	unsigned int clk_count;
177*4882a593Smuzhiyun 	struct clk **clks;
178*4882a593Smuzhiyun #endif
179*4882a593Smuzhiyun #if defined CONFIG_OF && defined CONFIG_REGULATOR
180*4882a593Smuzhiyun 	bool regulators_enabled;
181*4882a593Smuzhiyun 	u32 regulator_count;
182*4882a593Smuzhiyun 	struct regulator **regulators;
183*4882a593Smuzhiyun #endif
184*4882a593Smuzhiyun };
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun #if defined CONFIG_OF && defined CONFIG_COMMON_CLK
187*4882a593Smuzhiyun /*
188*4882a593Smuzhiyun  * Clock handling code.
189*4882a593Smuzhiyun  *
190*4882a593Smuzhiyun  * Here we handle the clocks property of our "simple-framebuffer" dt node.
191*4882a593Smuzhiyun  * This is necessary so that we can make sure that any clocks needed by
192*4882a593Smuzhiyun  * the display engine that the bootloader set up for us (and for which it
193*4882a593Smuzhiyun  * provided a simplefb dt node), stay up, for the life of the simplefb
194*4882a593Smuzhiyun  * driver.
195*4882a593Smuzhiyun  *
196*4882a593Smuzhiyun  * When the driver unloads, we cleanly disable, and then release the clocks.
197*4882a593Smuzhiyun  *
198*4882a593Smuzhiyun  * We only complain about errors here, no action is taken as the most likely
199*4882a593Smuzhiyun  * error can only happen due to a mismatch between the bootloader which set
200*4882a593Smuzhiyun  * up simplefb, and the clock definitions in the device tree. Chances are
201*4882a593Smuzhiyun  * that there are no adverse effects, and if there are, a clean teardown of
202*4882a593Smuzhiyun  * the fb probe will not help us much either. So just complain and carry on,
203*4882a593Smuzhiyun  * and hope that the user actually gets a working fb at the end of things.
204*4882a593Smuzhiyun  */
simplefb_clocks_get(struct simplefb_par * par,struct platform_device * pdev)205*4882a593Smuzhiyun static int simplefb_clocks_get(struct simplefb_par *par,
206*4882a593Smuzhiyun 			       struct platform_device *pdev)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	struct device_node *np = pdev->dev.of_node;
209*4882a593Smuzhiyun 	struct clk *clock;
210*4882a593Smuzhiyun 	int i;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	if (dev_get_platdata(&pdev->dev) || !np)
213*4882a593Smuzhiyun 		return 0;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	par->clk_count = of_clk_get_parent_count(np);
216*4882a593Smuzhiyun 	if (!par->clk_count)
217*4882a593Smuzhiyun 		return 0;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	par->clks = kcalloc(par->clk_count, sizeof(struct clk *), GFP_KERNEL);
220*4882a593Smuzhiyun 	if (!par->clks)
221*4882a593Smuzhiyun 		return -ENOMEM;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	for (i = 0; i < par->clk_count; i++) {
224*4882a593Smuzhiyun 		clock = of_clk_get(np, i);
225*4882a593Smuzhiyun 		if (IS_ERR(clock)) {
226*4882a593Smuzhiyun 			if (PTR_ERR(clock) == -EPROBE_DEFER) {
227*4882a593Smuzhiyun 				while (--i >= 0) {
228*4882a593Smuzhiyun 					if (par->clks[i])
229*4882a593Smuzhiyun 						clk_put(par->clks[i]);
230*4882a593Smuzhiyun 				}
231*4882a593Smuzhiyun 				kfree(par->clks);
232*4882a593Smuzhiyun 				return -EPROBE_DEFER;
233*4882a593Smuzhiyun 			}
234*4882a593Smuzhiyun 			dev_err(&pdev->dev, "%s: clock %d not found: %ld\n",
235*4882a593Smuzhiyun 				__func__, i, PTR_ERR(clock));
236*4882a593Smuzhiyun 			continue;
237*4882a593Smuzhiyun 		}
238*4882a593Smuzhiyun 		par->clks[i] = clock;
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	return 0;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
simplefb_clocks_enable(struct simplefb_par * par,struct platform_device * pdev)244*4882a593Smuzhiyun static void simplefb_clocks_enable(struct simplefb_par *par,
245*4882a593Smuzhiyun 				   struct platform_device *pdev)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	int i, ret;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	for (i = 0; i < par->clk_count; i++) {
250*4882a593Smuzhiyun 		if (par->clks[i]) {
251*4882a593Smuzhiyun 			ret = clk_prepare_enable(par->clks[i]);
252*4882a593Smuzhiyun 			if (ret) {
253*4882a593Smuzhiyun 				dev_err(&pdev->dev,
254*4882a593Smuzhiyun 					"%s: failed to enable clock %d: %d\n",
255*4882a593Smuzhiyun 					__func__, i, ret);
256*4882a593Smuzhiyun 				clk_put(par->clks[i]);
257*4882a593Smuzhiyun 				par->clks[i] = NULL;
258*4882a593Smuzhiyun 			}
259*4882a593Smuzhiyun 		}
260*4882a593Smuzhiyun 	}
261*4882a593Smuzhiyun 	par->clks_enabled = true;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
simplefb_clocks_destroy(struct simplefb_par * par)264*4882a593Smuzhiyun static void simplefb_clocks_destroy(struct simplefb_par *par)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	int i;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	if (!par->clks)
269*4882a593Smuzhiyun 		return;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	for (i = 0; i < par->clk_count; i++) {
272*4882a593Smuzhiyun 		if (par->clks[i]) {
273*4882a593Smuzhiyun 			if (par->clks_enabled)
274*4882a593Smuzhiyun 				clk_disable_unprepare(par->clks[i]);
275*4882a593Smuzhiyun 			clk_put(par->clks[i]);
276*4882a593Smuzhiyun 		}
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	kfree(par->clks);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun #else
simplefb_clocks_get(struct simplefb_par * par,struct platform_device * pdev)282*4882a593Smuzhiyun static int simplefb_clocks_get(struct simplefb_par *par,
283*4882a593Smuzhiyun 	struct platform_device *pdev) { return 0; }
simplefb_clocks_enable(struct simplefb_par * par,struct platform_device * pdev)284*4882a593Smuzhiyun static void simplefb_clocks_enable(struct simplefb_par *par,
285*4882a593Smuzhiyun 	struct platform_device *pdev) { }
simplefb_clocks_destroy(struct simplefb_par * par)286*4882a593Smuzhiyun static void simplefb_clocks_destroy(struct simplefb_par *par) { }
287*4882a593Smuzhiyun #endif
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun #if defined CONFIG_OF && defined CONFIG_REGULATOR
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun #define SUPPLY_SUFFIX "-supply"
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun /*
294*4882a593Smuzhiyun  * Regulator handling code.
295*4882a593Smuzhiyun  *
296*4882a593Smuzhiyun  * Here we handle the num-supplies and vin*-supply properties of our
297*4882a593Smuzhiyun  * "simple-framebuffer" dt node. This is necessary so that we can make sure
298*4882a593Smuzhiyun  * that any regulators needed by the display hardware that the bootloader
299*4882a593Smuzhiyun  * set up for us (and for which it provided a simplefb dt node), stay up,
300*4882a593Smuzhiyun  * for the life of the simplefb driver.
301*4882a593Smuzhiyun  *
302*4882a593Smuzhiyun  * When the driver unloads, we cleanly disable, and then release the
303*4882a593Smuzhiyun  * regulators.
304*4882a593Smuzhiyun  *
305*4882a593Smuzhiyun  * We only complain about errors here, no action is taken as the most likely
306*4882a593Smuzhiyun  * error can only happen due to a mismatch between the bootloader which set
307*4882a593Smuzhiyun  * up simplefb, and the regulator definitions in the device tree. Chances are
308*4882a593Smuzhiyun  * that there are no adverse effects, and if there are, a clean teardown of
309*4882a593Smuzhiyun  * the fb probe will not help us much either. So just complain and carry on,
310*4882a593Smuzhiyun  * and hope that the user actually gets a working fb at the end of things.
311*4882a593Smuzhiyun  */
simplefb_regulators_get(struct simplefb_par * par,struct platform_device * pdev)312*4882a593Smuzhiyun static int simplefb_regulators_get(struct simplefb_par *par,
313*4882a593Smuzhiyun 				   struct platform_device *pdev)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	struct device_node *np = pdev->dev.of_node;
316*4882a593Smuzhiyun 	struct property *prop;
317*4882a593Smuzhiyun 	struct regulator *regulator;
318*4882a593Smuzhiyun 	const char *p;
319*4882a593Smuzhiyun 	int count = 0, i = 0;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	if (dev_get_platdata(&pdev->dev) || !np)
322*4882a593Smuzhiyun 		return 0;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	/* Count the number of regulator supplies */
325*4882a593Smuzhiyun 	for_each_property_of_node(np, prop) {
326*4882a593Smuzhiyun 		p = strstr(prop->name, SUPPLY_SUFFIX);
327*4882a593Smuzhiyun 		if (p && p != prop->name)
328*4882a593Smuzhiyun 			count++;
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	if (!count)
332*4882a593Smuzhiyun 		return 0;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	par->regulators = devm_kcalloc(&pdev->dev, count,
335*4882a593Smuzhiyun 				       sizeof(struct regulator *), GFP_KERNEL);
336*4882a593Smuzhiyun 	if (!par->regulators)
337*4882a593Smuzhiyun 		return -ENOMEM;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	/* Get all the regulators */
340*4882a593Smuzhiyun 	for_each_property_of_node(np, prop) {
341*4882a593Smuzhiyun 		char name[32]; /* 32 is max size of property name */
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 		p = strstr(prop->name, SUPPLY_SUFFIX);
344*4882a593Smuzhiyun 		if (!p || p == prop->name)
345*4882a593Smuzhiyun 			continue;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 		strlcpy(name, prop->name,
348*4882a593Smuzhiyun 			strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1);
349*4882a593Smuzhiyun 		regulator = devm_regulator_get_optional(&pdev->dev, name);
350*4882a593Smuzhiyun 		if (IS_ERR(regulator)) {
351*4882a593Smuzhiyun 			if (PTR_ERR(regulator) == -EPROBE_DEFER)
352*4882a593Smuzhiyun 				return -EPROBE_DEFER;
353*4882a593Smuzhiyun 			dev_err(&pdev->dev, "regulator %s not found: %ld\n",
354*4882a593Smuzhiyun 				name, PTR_ERR(regulator));
355*4882a593Smuzhiyun 			continue;
356*4882a593Smuzhiyun 		}
357*4882a593Smuzhiyun 		par->regulators[i++] = regulator;
358*4882a593Smuzhiyun 	}
359*4882a593Smuzhiyun 	par->regulator_count = i;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	return 0;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun 
simplefb_regulators_enable(struct simplefb_par * par,struct platform_device * pdev)364*4882a593Smuzhiyun static void simplefb_regulators_enable(struct simplefb_par *par,
365*4882a593Smuzhiyun 				       struct platform_device *pdev)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	int i, ret;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	/* Enable all the regulators */
370*4882a593Smuzhiyun 	for (i = 0; i < par->regulator_count; i++) {
371*4882a593Smuzhiyun 		ret = regulator_enable(par->regulators[i]);
372*4882a593Smuzhiyun 		if (ret) {
373*4882a593Smuzhiyun 			dev_err(&pdev->dev,
374*4882a593Smuzhiyun 				"failed to enable regulator %d: %d\n",
375*4882a593Smuzhiyun 				i, ret);
376*4882a593Smuzhiyun 			devm_regulator_put(par->regulators[i]);
377*4882a593Smuzhiyun 			par->regulators[i] = NULL;
378*4882a593Smuzhiyun 		}
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 	par->regulators_enabled = true;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
simplefb_regulators_destroy(struct simplefb_par * par)383*4882a593Smuzhiyun static void simplefb_regulators_destroy(struct simplefb_par *par)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun 	int i;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	if (!par->regulators || !par->regulators_enabled)
388*4882a593Smuzhiyun 		return;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	for (i = 0; i < par->regulator_count; i++)
391*4882a593Smuzhiyun 		if (par->regulators[i])
392*4882a593Smuzhiyun 			regulator_disable(par->regulators[i]);
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun #else
simplefb_regulators_get(struct simplefb_par * par,struct platform_device * pdev)395*4882a593Smuzhiyun static int simplefb_regulators_get(struct simplefb_par *par,
396*4882a593Smuzhiyun 	struct platform_device *pdev) { return 0; }
simplefb_regulators_enable(struct simplefb_par * par,struct platform_device * pdev)397*4882a593Smuzhiyun static void simplefb_regulators_enable(struct simplefb_par *par,
398*4882a593Smuzhiyun 	struct platform_device *pdev) { }
simplefb_regulators_destroy(struct simplefb_par * par)399*4882a593Smuzhiyun static void simplefb_regulators_destroy(struct simplefb_par *par) { }
400*4882a593Smuzhiyun #endif
401*4882a593Smuzhiyun 
simplefb_probe(struct platform_device * pdev)402*4882a593Smuzhiyun static int simplefb_probe(struct platform_device *pdev)
403*4882a593Smuzhiyun {
404*4882a593Smuzhiyun 	int ret;
405*4882a593Smuzhiyun 	struct simplefb_params params;
406*4882a593Smuzhiyun 	struct fb_info *info;
407*4882a593Smuzhiyun 	struct simplefb_par *par;
408*4882a593Smuzhiyun 	struct resource *mem;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	if (fb_get_options("simplefb", NULL))
411*4882a593Smuzhiyun 		return -ENODEV;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	ret = -ENODEV;
414*4882a593Smuzhiyun 	if (dev_get_platdata(&pdev->dev))
415*4882a593Smuzhiyun 		ret = simplefb_parse_pd(pdev, &params);
416*4882a593Smuzhiyun 	else if (pdev->dev.of_node)
417*4882a593Smuzhiyun 		ret = simplefb_parse_dt(pdev, &params);
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	if (ret)
420*4882a593Smuzhiyun 		return ret;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
423*4882a593Smuzhiyun 	if (!mem) {
424*4882a593Smuzhiyun 		dev_err(&pdev->dev, "No memory resource\n");
425*4882a593Smuzhiyun 		return -EINVAL;
426*4882a593Smuzhiyun 	}
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev);
429*4882a593Smuzhiyun 	if (!info)
430*4882a593Smuzhiyun 		return -ENOMEM;
431*4882a593Smuzhiyun 	platform_set_drvdata(pdev, info);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	par = info->par;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	info->fix = simplefb_fix;
436*4882a593Smuzhiyun 	info->fix.smem_start = mem->start;
437*4882a593Smuzhiyun 	info->fix.smem_len = resource_size(mem);
438*4882a593Smuzhiyun 	info->fix.line_length = params.stride;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	info->var = simplefb_var;
441*4882a593Smuzhiyun 	info->var.xres = params.width;
442*4882a593Smuzhiyun 	info->var.yres = params.height;
443*4882a593Smuzhiyun 	info->var.xres_virtual = params.width;
444*4882a593Smuzhiyun 	info->var.yres_virtual = params.height;
445*4882a593Smuzhiyun 	info->var.bits_per_pixel = params.format->bits_per_pixel;
446*4882a593Smuzhiyun 	info->var.red = params.format->red;
447*4882a593Smuzhiyun 	info->var.green = params.format->green;
448*4882a593Smuzhiyun 	info->var.blue = params.format->blue;
449*4882a593Smuzhiyun 	info->var.transp = params.format->transp;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	info->apertures = alloc_apertures(1);
452*4882a593Smuzhiyun 	if (!info->apertures) {
453*4882a593Smuzhiyun 		ret = -ENOMEM;
454*4882a593Smuzhiyun 		goto error_fb_release;
455*4882a593Smuzhiyun 	}
456*4882a593Smuzhiyun 	info->apertures->ranges[0].base = info->fix.smem_start;
457*4882a593Smuzhiyun 	info->apertures->ranges[0].size = info->fix.smem_len;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	info->fbops = &simplefb_ops;
460*4882a593Smuzhiyun 	info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
461*4882a593Smuzhiyun 	info->screen_base = ioremap_wc(info->fix.smem_start,
462*4882a593Smuzhiyun 				       info->fix.smem_len);
463*4882a593Smuzhiyun 	if (!info->screen_base) {
464*4882a593Smuzhiyun 		ret = -ENOMEM;
465*4882a593Smuzhiyun 		goto error_fb_release;
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 	info->pseudo_palette = par->palette;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	ret = simplefb_clocks_get(par, pdev);
470*4882a593Smuzhiyun 	if (ret < 0)
471*4882a593Smuzhiyun 		goto error_unmap;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	ret = simplefb_regulators_get(par, pdev);
474*4882a593Smuzhiyun 	if (ret < 0)
475*4882a593Smuzhiyun 		goto error_clocks;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	simplefb_clocks_enable(par, pdev);
478*4882a593Smuzhiyun 	simplefb_regulators_enable(par, pdev);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
481*4882a593Smuzhiyun 			     info->fix.smem_start, info->fix.smem_len,
482*4882a593Smuzhiyun 			     info->screen_base);
483*4882a593Smuzhiyun 	dev_info(&pdev->dev, "format=%s, mode=%dx%dx%d, linelength=%d\n",
484*4882a593Smuzhiyun 			     params.format->name,
485*4882a593Smuzhiyun 			     info->var.xres, info->var.yres,
486*4882a593Smuzhiyun 			     info->var.bits_per_pixel, info->fix.line_length);
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	ret = register_framebuffer(info);
489*4882a593Smuzhiyun 	if (ret < 0) {
490*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
491*4882a593Smuzhiyun 		goto error_regulators;
492*4882a593Smuzhiyun 	}
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	return 0;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun error_regulators:
499*4882a593Smuzhiyun 	simplefb_regulators_destroy(par);
500*4882a593Smuzhiyun error_clocks:
501*4882a593Smuzhiyun 	simplefb_clocks_destroy(par);
502*4882a593Smuzhiyun error_unmap:
503*4882a593Smuzhiyun 	iounmap(info->screen_base);
504*4882a593Smuzhiyun error_fb_release:
505*4882a593Smuzhiyun 	framebuffer_release(info);
506*4882a593Smuzhiyun 	return ret;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun 
simplefb_remove(struct platform_device * pdev)509*4882a593Smuzhiyun static int simplefb_remove(struct platform_device *pdev)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	struct fb_info *info = platform_get_drvdata(pdev);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	unregister_framebuffer(info);
514*4882a593Smuzhiyun 	framebuffer_release(info);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	return 0;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun static const struct of_device_id simplefb_of_match[] = {
520*4882a593Smuzhiyun 	{ .compatible = "simple-framebuffer", },
521*4882a593Smuzhiyun 	{ },
522*4882a593Smuzhiyun };
523*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, simplefb_of_match);
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun static struct platform_driver simplefb_driver = {
526*4882a593Smuzhiyun 	.driver = {
527*4882a593Smuzhiyun 		.name = "simple-framebuffer",
528*4882a593Smuzhiyun 		.of_match_table = simplefb_of_match,
529*4882a593Smuzhiyun 	},
530*4882a593Smuzhiyun 	.probe = simplefb_probe,
531*4882a593Smuzhiyun 	.remove = simplefb_remove,
532*4882a593Smuzhiyun };
533*4882a593Smuzhiyun 
simplefb_init(void)534*4882a593Smuzhiyun static int __init simplefb_init(void)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun 	int ret;
537*4882a593Smuzhiyun 	struct device_node *np;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	ret = platform_driver_register(&simplefb_driver);
540*4882a593Smuzhiyun 	if (ret)
541*4882a593Smuzhiyun 		return ret;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	if (IS_ENABLED(CONFIG_OF_ADDRESS) && of_chosen) {
544*4882a593Smuzhiyun 		for_each_child_of_node(of_chosen, np) {
545*4882a593Smuzhiyun 			if (of_device_is_compatible(np, "simple-framebuffer"))
546*4882a593Smuzhiyun 				of_platform_device_create(np, NULL, NULL);
547*4882a593Smuzhiyun 		}
548*4882a593Smuzhiyun 	}
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	return 0;
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun fs_initcall(simplefb_init);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
556*4882a593Smuzhiyun MODULE_DESCRIPTION("Simple framebuffer driver");
557*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
558