ARM: debug: qcom: add UART addresses to Kconfig help for APQ8084
[pandora-kernel.git] / drivers / video / fbdev / omap2 / displays-new / panel-dpi.c
1 /*
2  * Generic MIPI DPI Panel Driver
3  *
4  * Copyright (C) 2013 Texas Instruments
5  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  */
11
12 #include <linux/gpio.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16
17 #include <video/omapdss.h>
18 #include <video/omap-panel-data.h>
19
20 struct panel_drv_data {
21         struct omap_dss_device dssdev;
22         struct omap_dss_device *in;
23
24         int data_lines;
25
26         struct omap_video_timings videomode;
27
28         int backlight_gpio;
29         int enable_gpio;
30 };
31
32 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
33
34 static int panel_dpi_connect(struct omap_dss_device *dssdev)
35 {
36         struct panel_drv_data *ddata = to_panel_data(dssdev);
37         struct omap_dss_device *in = ddata->in;
38         int r;
39
40         if (omapdss_device_is_connected(dssdev))
41                 return 0;
42
43         r = in->ops.dpi->connect(in, dssdev);
44         if (r)
45                 return r;
46
47         return 0;
48 }
49
50 static void panel_dpi_disconnect(struct omap_dss_device *dssdev)
51 {
52         struct panel_drv_data *ddata = to_panel_data(dssdev);
53         struct omap_dss_device *in = ddata->in;
54
55         if (!omapdss_device_is_connected(dssdev))
56                 return;
57
58         in->ops.dpi->disconnect(in, dssdev);
59 }
60
61 static int panel_dpi_enable(struct omap_dss_device *dssdev)
62 {
63         struct panel_drv_data *ddata = to_panel_data(dssdev);
64         struct omap_dss_device *in = ddata->in;
65         int r;
66
67         if (!omapdss_device_is_connected(dssdev))
68                 return -ENODEV;
69
70         if (omapdss_device_is_enabled(dssdev))
71                 return 0;
72
73         in->ops.dpi->set_data_lines(in, ddata->data_lines);
74         in->ops.dpi->set_timings(in, &ddata->videomode);
75
76         r = in->ops.dpi->enable(in);
77         if (r)
78                 return r;
79
80         if (gpio_is_valid(ddata->enable_gpio))
81                 gpio_set_value_cansleep(ddata->enable_gpio, 1);
82
83         if (gpio_is_valid(ddata->backlight_gpio))
84                 gpio_set_value_cansleep(ddata->backlight_gpio, 1);
85
86         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
87
88         return 0;
89 }
90
91 static void panel_dpi_disable(struct omap_dss_device *dssdev)
92 {
93         struct panel_drv_data *ddata = to_panel_data(dssdev);
94         struct omap_dss_device *in = ddata->in;
95
96         if (!omapdss_device_is_enabled(dssdev))
97                 return;
98
99         if (gpio_is_valid(ddata->enable_gpio))
100                 gpio_set_value_cansleep(ddata->enable_gpio, 0);
101
102         if (gpio_is_valid(ddata->backlight_gpio))
103                 gpio_set_value_cansleep(ddata->backlight_gpio, 0);
104
105         in->ops.dpi->disable(in);
106
107         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
108 }
109
110 static void panel_dpi_set_timings(struct omap_dss_device *dssdev,
111                 struct omap_video_timings *timings)
112 {
113         struct panel_drv_data *ddata = to_panel_data(dssdev);
114         struct omap_dss_device *in = ddata->in;
115
116         ddata->videomode = *timings;
117         dssdev->panel.timings = *timings;
118
119         in->ops.dpi->set_timings(in, timings);
120 }
121
122 static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
123                 struct omap_video_timings *timings)
124 {
125         struct panel_drv_data *ddata = to_panel_data(dssdev);
126
127         *timings = ddata->videomode;
128 }
129
130 static int panel_dpi_check_timings(struct omap_dss_device *dssdev,
131                 struct omap_video_timings *timings)
132 {
133         struct panel_drv_data *ddata = to_panel_data(dssdev);
134         struct omap_dss_device *in = ddata->in;
135
136         return in->ops.dpi->check_timings(in, timings);
137 }
138
139 static struct omap_dss_driver panel_dpi_ops = {
140         .connect        = panel_dpi_connect,
141         .disconnect     = panel_dpi_disconnect,
142
143         .enable         = panel_dpi_enable,
144         .disable        = panel_dpi_disable,
145
146         .set_timings    = panel_dpi_set_timings,
147         .get_timings    = panel_dpi_get_timings,
148         .check_timings  = panel_dpi_check_timings,
149
150         .get_resolution = omapdss_default_get_resolution,
151 };
152
153 static int panel_dpi_probe_pdata(struct platform_device *pdev)
154 {
155         const struct panel_dpi_platform_data *pdata;
156         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
157         struct omap_dss_device *dssdev, *in;
158         struct videomode vm;
159
160         pdata = dev_get_platdata(&pdev->dev);
161
162         in = omap_dss_find_output(pdata->source);
163         if (in == NULL) {
164                 dev_err(&pdev->dev, "failed to find video source '%s'\n",
165                                 pdata->source);
166                 return -EPROBE_DEFER;
167         }
168
169         ddata->in = in;
170
171         ddata->data_lines = pdata->data_lines;
172
173         videomode_from_timing(pdata->display_timing, &vm);
174         videomode_to_omap_video_timings(&vm, &ddata->videomode);
175
176         dssdev = &ddata->dssdev;
177         dssdev->name = pdata->name;
178
179         ddata->enable_gpio = pdata->enable_gpio;
180         ddata->backlight_gpio = pdata->backlight_gpio;
181
182         return 0;
183 }
184
185 static int panel_dpi_probe(struct platform_device *pdev)
186 {
187         struct panel_drv_data *ddata;
188         struct omap_dss_device *dssdev;
189         int r;
190
191         ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
192         if (ddata == NULL)
193                 return -ENOMEM;
194
195         platform_set_drvdata(pdev, ddata);
196
197         if (dev_get_platdata(&pdev->dev)) {
198                 r = panel_dpi_probe_pdata(pdev);
199                 if (r)
200                         return r;
201         } else {
202                 return -ENODEV;
203         }
204
205         if (gpio_is_valid(ddata->enable_gpio)) {
206                 r = devm_gpio_request_one(&pdev->dev, ddata->enable_gpio,
207                                 GPIOF_OUT_INIT_LOW, "panel enable");
208                 if (r)
209                         goto err_gpio;
210         }
211
212         if (gpio_is_valid(ddata->backlight_gpio)) {
213                 r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio,
214                                 GPIOF_OUT_INIT_LOW, "panel backlight");
215                 if (r)
216                         goto err_gpio;
217         }
218
219         dssdev = &ddata->dssdev;
220         dssdev->dev = &pdev->dev;
221         dssdev->driver = &panel_dpi_ops;
222         dssdev->type = OMAP_DISPLAY_TYPE_DPI;
223         dssdev->owner = THIS_MODULE;
224         dssdev->panel.timings = ddata->videomode;
225         dssdev->phy.dpi.data_lines = ddata->data_lines;
226
227         r = omapdss_register_display(dssdev);
228         if (r) {
229                 dev_err(&pdev->dev, "Failed to register panel\n");
230                 goto err_reg;
231         }
232
233         return 0;
234
235 err_reg:
236 err_gpio:
237         omap_dss_put_device(ddata->in);
238         return r;
239 }
240
241 static int __exit panel_dpi_remove(struct platform_device *pdev)
242 {
243         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
244         struct omap_dss_device *dssdev = &ddata->dssdev;
245         struct omap_dss_device *in = ddata->in;
246
247         omapdss_unregister_display(dssdev);
248
249         panel_dpi_disable(dssdev);
250         panel_dpi_disconnect(dssdev);
251
252         omap_dss_put_device(in);
253
254         return 0;
255 }
256
257 static struct platform_driver panel_dpi_driver = {
258         .probe = panel_dpi_probe,
259         .remove = __exit_p(panel_dpi_remove),
260         .driver = {
261                 .name = "panel-dpi",
262                 .owner = THIS_MODULE,
263         },
264 };
265
266 module_platform_driver(panel_dpi_driver);
267
268 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
269 MODULE_DESCRIPTION("Generic MIPI DPI Panel Driver");
270 MODULE_LICENSE("GPL");