panel-simple.c revision 280921de7241ee63184c8baa89ec3fe0122dedb3
1/*
2 * Copyright (C) 2013, NVIDIA Corporation.  All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sub license,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#include <linux/backlight.h>
25#include <linux/gpio.h>
26#include <linux/module.h>
27#include <linux/of_gpio.h>
28#include <linux/of_platform.h>
29#include <linux/platform_device.h>
30#include <linux/regulator/consumer.h>
31
32#include <drm/drmP.h>
33#include <drm/drm_crtc.h>
34#include <drm/drm_panel.h>
35
36struct panel_desc {
37	const struct drm_display_mode *modes;
38	unsigned int num_modes;
39
40	struct {
41		unsigned int width;
42		unsigned int height;
43	} size;
44};
45
46/* TODO: convert to gpiod_*() API once it's been merged */
47#define GPIO_ACTIVE_LOW	(1 << 0)
48
49struct panel_simple {
50	struct drm_panel base;
51	bool enabled;
52
53	const struct panel_desc *desc;
54
55	struct backlight_device *backlight;
56	struct regulator *supply;
57	struct i2c_adapter *ddc;
58
59	unsigned long enable_gpio_flags;
60	int enable_gpio;
61};
62
63static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
64{
65	return container_of(panel, struct panel_simple, base);
66}
67
68static int panel_simple_get_fixed_modes(struct panel_simple *panel)
69{
70	struct drm_connector *connector = panel->base.connector;
71	struct drm_device *drm = panel->base.drm;
72	struct drm_display_mode *mode;
73	unsigned int i, num = 0;
74
75	if (!panel->desc)
76		return 0;
77
78	for (i = 0; i < panel->desc->num_modes; i++) {
79		const struct drm_display_mode *m = &panel->desc->modes[i];
80
81		mode = drm_mode_duplicate(drm, m);
82		if (!mode) {
83			dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
84				m->hdisplay, m->vdisplay, m->vrefresh);
85			continue;
86		}
87
88		drm_mode_set_name(mode);
89
90		drm_mode_probed_add(connector, mode);
91		num++;
92	}
93
94	connector->display_info.width_mm = panel->desc->size.width;
95	connector->display_info.height_mm = panel->desc->size.height;
96
97	return num;
98}
99
100static int panel_simple_disable(struct drm_panel *panel)
101{
102	struct panel_simple *p = to_panel_simple(panel);
103
104	if (!p->enabled)
105		return 0;
106
107	if (p->backlight) {
108		p->backlight->props.power = FB_BLANK_POWERDOWN;
109		backlight_update_status(p->backlight);
110	}
111
112	if (gpio_is_valid(p->enable_gpio)) {
113		if (p->enable_gpio_flags & GPIO_ACTIVE_LOW)
114			gpio_set_value(p->enable_gpio, 1);
115		else
116			gpio_set_value(p->enable_gpio, 0);
117	}
118
119	regulator_disable(p->supply);
120	p->enabled = false;
121
122	return 0;
123}
124
125static int panel_simple_enable(struct drm_panel *panel)
126{
127	struct panel_simple *p = to_panel_simple(panel);
128	int err;
129
130	if (p->enabled)
131		return 0;
132
133	err = regulator_enable(p->supply);
134	if (err < 0) {
135		dev_err(panel->dev, "failed to enable supply: %d\n", err);
136		return err;
137	}
138
139	if (gpio_is_valid(p->enable_gpio)) {
140		if (p->enable_gpio_flags & GPIO_ACTIVE_LOW)
141			gpio_set_value(p->enable_gpio, 0);
142		else
143			gpio_set_value(p->enable_gpio, 1);
144	}
145
146	if (p->backlight) {
147		p->backlight->props.power = FB_BLANK_UNBLANK;
148		backlight_update_status(p->backlight);
149	}
150
151	p->enabled = true;
152
153	return 0;
154}
155
156static int panel_simple_get_modes(struct drm_panel *panel)
157{
158	struct panel_simple *p = to_panel_simple(panel);
159	int num = 0;
160
161	/* probe EDID if a DDC bus is available */
162	if (p->ddc) {
163		struct edid *edid = drm_get_edid(panel->connector, p->ddc);
164		if (edid) {
165			num += drm_add_edid_modes(panel->connector, edid);
166			kfree(edid);
167		}
168	}
169
170	/* add hard-coded panel modes */
171	num += panel_simple_get_fixed_modes(p);
172
173	return num;
174}
175
176static const struct drm_panel_funcs panel_simple_funcs = {
177	.disable = panel_simple_disable,
178	.enable = panel_simple_enable,
179	.get_modes = panel_simple_get_modes,
180};
181
182static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
183{
184	struct device_node *backlight, *ddc;
185	struct panel_simple *panel;
186	enum of_gpio_flags flags;
187	int err;
188
189	panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
190	if (!panel)
191		return -ENOMEM;
192
193	panel->enabled = false;
194	panel->desc = desc;
195
196	panel->supply = devm_regulator_get(dev, "power");
197	if (IS_ERR(panel->supply))
198		return PTR_ERR(panel->supply);
199
200	panel->enable_gpio = of_get_named_gpio_flags(dev->of_node,
201						     "enable-gpios", 0,
202						     &flags);
203	if (gpio_is_valid(panel->enable_gpio)) {
204		unsigned int value;
205
206		if (flags & OF_GPIO_ACTIVE_LOW)
207			panel->enable_gpio_flags |= GPIO_ACTIVE_LOW;
208
209		err = gpio_request(panel->enable_gpio, "enable");
210		if (err < 0) {
211			dev_err(dev, "failed to request GPIO#%u: %d\n",
212				panel->enable_gpio, err);
213			return err;
214		}
215
216		value = (panel->enable_gpio_flags & GPIO_ACTIVE_LOW) != 0;
217
218		err = gpio_direction_output(panel->enable_gpio, value);
219		if (err < 0) {
220			dev_err(dev, "failed to setup GPIO%u: %d\n",
221				panel->enable_gpio, err);
222			goto free_gpio;
223		}
224	}
225
226	backlight = of_parse_phandle(dev->of_node, "backlight", 0);
227	if (backlight) {
228		panel->backlight = of_find_backlight_by_node(backlight);
229		of_node_put(backlight);
230
231		if (!panel->backlight) {
232			err = -EPROBE_DEFER;
233			goto free_gpio;
234		}
235	}
236
237	ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
238	if (ddc) {
239		panel->ddc = of_find_i2c_adapter_by_node(ddc);
240		of_node_put(ddc);
241
242		if (!panel->ddc) {
243			err = -EPROBE_DEFER;
244			goto free_backlight;
245		}
246	}
247
248	drm_panel_init(&panel->base);
249	panel->base.dev = dev;
250	panel->base.funcs = &panel_simple_funcs;
251
252	err = drm_panel_add(&panel->base);
253	if (err < 0)
254		goto free_ddc;
255
256	dev_set_drvdata(dev, panel);
257
258	return 0;
259
260free_ddc:
261	if (panel->ddc)
262		put_device(&panel->ddc->dev);
263free_backlight:
264	if (panel->backlight)
265		put_device(&panel->backlight->dev);
266free_gpio:
267	if (gpio_is_valid(panel->enable_gpio))
268		gpio_free(panel->enable_gpio);
269
270	return err;
271}
272
273static int panel_simple_remove(struct device *dev)
274{
275	struct panel_simple *panel = dev_get_drvdata(dev);
276
277	drm_panel_detach(&panel->base);
278	drm_panel_remove(&panel->base);
279
280	panel_simple_disable(&panel->base);
281
282	if (panel->ddc)
283		put_device(&panel->ddc->dev);
284
285	if (panel->backlight)
286		put_device(&panel->backlight->dev);
287
288	if (gpio_is_valid(panel->enable_gpio))
289		gpio_free(panel->enable_gpio);
290
291	regulator_disable(panel->supply);
292
293	return 0;
294}
295
296static const struct drm_display_mode auo_b101aw03_mode = {
297	.clock = 51450,
298	.hdisplay = 1024,
299	.hsync_start = 1024 + 156,
300	.hsync_end = 1024 + 156 + 8,
301	.htotal = 1024 + 156 + 8 + 156,
302	.vdisplay = 600,
303	.vsync_start = 600 + 16,
304	.vsync_end = 600 + 16 + 6,
305	.vtotal = 600 + 16 + 6 + 16,
306	.vrefresh = 60,
307};
308
309static const struct panel_desc auo_b101aw03 = {
310	.modes = &auo_b101aw03_mode,
311	.num_modes = 1,
312	.size = {
313		.width = 223,
314		.height = 125,
315	},
316};
317
318static const struct drm_display_mode chunghwa_claa101wb01_mode = {
319	.clock = 69300,
320	.hdisplay = 1366,
321	.hsync_start = 1366 + 48,
322	.hsync_end = 1366 + 48 + 32,
323	.htotal = 1366 + 48 + 32 + 20,
324	.vdisplay = 768,
325	.vsync_start = 768 + 16,
326	.vsync_end = 768 + 16 + 8,
327	.vtotal = 768 + 16 + 8 + 16,
328	.vrefresh = 60,
329};
330
331static const struct panel_desc chunghwa_claa101wb01 = {
332	.modes = &chunghwa_claa101wb01_mode,
333	.num_modes = 1,
334	.size = {
335		.width = 223,
336		.height = 125,
337	},
338};
339
340static const struct of_device_id platform_of_match[] = {
341	{
342		.compatible = "auo,b101aw03",
343		.data = &auo_b101aw03,
344	}, {
345		.compatible = "chunghwa,claa101wb01",
346		.data = &chunghwa_claa101wb01
347	}, {
348		.compatible = "simple-panel",
349	}, {
350		/* sentinel */
351	}
352};
353MODULE_DEVICE_TABLE(of, platform_of_match);
354
355static int panel_simple_platform_probe(struct platform_device *pdev)
356{
357	const struct of_device_id *id;
358
359	id = of_match_node(platform_of_match, pdev->dev.of_node);
360	if (!id)
361		return -ENODEV;
362
363	return panel_simple_probe(&pdev->dev, id->data);
364}
365
366static int panel_simple_platform_remove(struct platform_device *pdev)
367{
368	return panel_simple_remove(&pdev->dev);
369}
370
371static struct platform_driver panel_simple_platform_driver = {
372	.driver = {
373		.name = "panel-simple",
374		.owner = THIS_MODULE,
375		.of_match_table = platform_of_match,
376	},
377	.probe = panel_simple_platform_probe,
378	.remove = panel_simple_platform_remove,
379};
380
381static const struct drm_display_mode panasonic_vvx10f004b00_mode = {
382	.clock = 157200,
383	.hdisplay = 1920,
384	.hsync_start = 1920 + 154,
385	.hsync_end = 1920 + 154 + 16,
386	.htotal = 1920 + 154 + 16 + 32,
387	.vdisplay = 1200,
388	.vsync_start = 1200 + 17,
389	.vsync_end = 1200 + 17 + 2,
390	.vtotal = 1200 + 17 + 2 + 16,
391	.vrefresh = 60,
392};
393
394static const struct panel_desc panasonic_vvx10f004b00 = {
395	.modes = &panasonic_vvx10f004b00_mode,
396	.num_modes = 1,
397	.size = {
398		.width = 217,
399		.height = 136,
400	},
401};
402
403static int __init panel_simple_init(void)
404{
405	return platform_driver_register(&panel_simple_platform_driver);
406}
407module_init(panel_simple_init);
408
409static void __exit panel_simple_exit(void)
410{
411	platform_driver_unregister(&panel_simple_platform_driver);
412}
413module_exit(panel_simple_exit);
414
415MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
416MODULE_DESCRIPTION("DRM Driver for Simple Panels");
417MODULE_LICENSE("GPL and additional rights");
418