Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
panel-tfp410.c
Go to the documentation of this file.
1 /*
2  * TFP410 DPI-to-DVI chip
3  *
4  * Copyright (C) 2011 Texas Instruments Inc
5  * Author: Tomi Valkeinen <[email protected]>
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  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <linux/module.h>
21 #include <linux/slab.h>
22 #include <video/omapdss.h>
23 #include <linux/i2c.h>
24 #include <linux/gpio.h>
25 #include <drm/drm_edid.h>
26 
28 
29 static const struct omap_video_timings tfp410_default_timings = {
30  .x_res = 640,
31  .y_res = 480,
32 
33  .pixel_clock = 23500,
34 
35  .hfp = 48,
36  .hsw = 32,
37  .hbp = 80,
38 
39  .vfp = 3,
40  .vsw = 4,
41  .vbp = 7,
42 
43  .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
44  .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
45  .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
46  .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
47  .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
48 };
49 
50 struct panel_drv_data {
51  struct omap_dss_device *dssdev;
52 
53  struct mutex lock;
54 
55  int pd_gpio;
56 
58 };
59 
60 static int tfp410_power_on(struct omap_dss_device *dssdev)
61 {
62  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
63  int r;
64 
65  if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
66  return 0;
67 
68  omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
69  omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
70 
71  r = omapdss_dpi_display_enable(dssdev);
72  if (r)
73  goto err0;
74 
75  if (gpio_is_valid(ddata->pd_gpio))
77 
78  return 0;
79 err0:
80  return r;
81 }
82 
83 static void tfp410_power_off(struct omap_dss_device *dssdev)
84 {
85  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
86 
87  if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
88  return;
89 
90  if (gpio_is_valid(ddata->pd_gpio))
92 
94 }
95 
96 static int tfp410_probe(struct omap_dss_device *dssdev)
97 {
98  struct panel_drv_data *ddata;
99  int r;
100  int i2c_bus_num;
101 
102  ddata = devm_kzalloc(&dssdev->dev, sizeof(*ddata), GFP_KERNEL);
103  if (!ddata)
104  return -ENOMEM;
105 
106  dssdev->panel.timings = tfp410_default_timings;
107 
108  ddata->dssdev = dssdev;
109  mutex_init(&ddata->lock);
110 
111  if (dssdev->data) {
112  struct tfp410_platform_data *pdata = dssdev->data;
113 
114  ddata->pd_gpio = pdata->power_down_gpio;
115  i2c_bus_num = pdata->i2c_bus_num;
116  } else {
117  ddata->pd_gpio = -1;
118  i2c_bus_num = -1;
119  }
120 
121  if (gpio_is_valid(ddata->pd_gpio)) {
122  r = devm_gpio_request_one(&dssdev->dev, ddata->pd_gpio,
123  GPIOF_OUT_INIT_LOW, "tfp410 pd");
124  if (r) {
125  dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n",
126  ddata->pd_gpio);
127  return r;
128  }
129  }
130 
131  if (i2c_bus_num != -1) {
132  struct i2c_adapter *adapter;
133 
134  adapter = i2c_get_adapter(i2c_bus_num);
135  if (!adapter) {
136  dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
137  i2c_bus_num);
138  return -EINVAL;
139  }
140 
141  ddata->i2c_adapter = adapter;
142  }
143 
144  dev_set_drvdata(&dssdev->dev, ddata);
145 
146  return 0;
147 }
148 
149 static void __exit tfp410_remove(struct omap_dss_device *dssdev)
150 {
151  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
152 
153  mutex_lock(&ddata->lock);
154 
155  if (ddata->i2c_adapter)
157 
158  dev_set_drvdata(&dssdev->dev, NULL);
159 
160  mutex_unlock(&ddata->lock);
161 }
162 
163 static int tfp410_enable(struct omap_dss_device *dssdev)
164 {
165  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
166  int r;
167 
168  mutex_lock(&ddata->lock);
169 
170  r = tfp410_power_on(dssdev);
171  if (r == 0)
172  dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
173 
174  mutex_unlock(&ddata->lock);
175 
176  return r;
177 }
178 
179 static void tfp410_disable(struct omap_dss_device *dssdev)
180 {
181  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
182 
183  mutex_lock(&ddata->lock);
184 
185  tfp410_power_off(dssdev);
186 
188 
189  mutex_unlock(&ddata->lock);
190 }
191 
192 static int tfp410_suspend(struct omap_dss_device *dssdev)
193 {
194  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
195 
196  mutex_lock(&ddata->lock);
197 
198  tfp410_power_off(dssdev);
199 
201 
202  mutex_unlock(&ddata->lock);
203 
204  return 0;
205 }
206 
207 static int tfp410_resume(struct omap_dss_device *dssdev)
208 {
209  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
210  int r;
211 
212  mutex_lock(&ddata->lock);
213 
214  r = tfp410_power_on(dssdev);
215  if (r == 0)
216  dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
217 
218  mutex_unlock(&ddata->lock);
219 
220  return r;
221 }
222 
223 static void tfp410_set_timings(struct omap_dss_device *dssdev,
224  struct omap_video_timings *timings)
225 {
226  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
227 
228  mutex_lock(&ddata->lock);
229  omapdss_dpi_set_timings(dssdev, timings);
230  dssdev->panel.timings = *timings;
231  mutex_unlock(&ddata->lock);
232 }
233 
234 static void tfp410_get_timings(struct omap_dss_device *dssdev,
235  struct omap_video_timings *timings)
236 {
237  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
238 
239  mutex_lock(&ddata->lock);
240  *timings = dssdev->panel.timings;
241  mutex_unlock(&ddata->lock);
242 }
243 
244 static int tfp410_check_timings(struct omap_dss_device *dssdev,
245  struct omap_video_timings *timings)
246 {
247  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
248  int r;
249 
250  mutex_lock(&ddata->lock);
251  r = dpi_check_timings(dssdev, timings);
252  mutex_unlock(&ddata->lock);
253 
254  return r;
255 }
256 
257 
258 static int tfp410_ddc_read(struct i2c_adapter *adapter,
259  unsigned char *buf, u16 count, u8 offset)
260 {
261  int r, retries;
262 
263  for (retries = 3; retries > 0; retries--) {
264  struct i2c_msg msgs[] = {
265  {
266  .addr = DDC_ADDR,
267  .flags = 0,
268  .len = 1,
269  .buf = &offset,
270  }, {
271  .addr = DDC_ADDR,
272  .flags = I2C_M_RD,
273  .len = count,
274  .buf = buf,
275  }
276  };
277 
278  r = i2c_transfer(adapter, msgs, 2);
279  if (r == 2)
280  return 0;
281 
282  if (r != -EAGAIN)
283  break;
284  }
285 
286  return r < 0 ? r : -EIO;
287 }
288 
289 static int tfp410_read_edid(struct omap_dss_device *dssdev,
290  u8 *edid, int len)
291 {
292  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
293  int r, l, bytes_read;
294 
295  mutex_lock(&ddata->lock);
296 
297  if (!ddata->i2c_adapter) {
298  r = -ENODEV;
299  goto err;
300  }
301 
302  l = min(EDID_LENGTH, len);
303  r = tfp410_ddc_read(ddata->i2c_adapter, edid, l, 0);
304  if (r)
305  goto err;
306 
307  bytes_read = l;
308 
309  /* if there are extensions, read second block */
310  if (len > EDID_LENGTH && edid[0x7e] > 0) {
311  l = min(EDID_LENGTH, len - EDID_LENGTH);
312 
313  r = tfp410_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH,
314  l, EDID_LENGTH);
315  if (r)
316  goto err;
317 
318  bytes_read += l;
319  }
320 
321  mutex_unlock(&ddata->lock);
322 
323  return bytes_read;
324 
325 err:
326  mutex_unlock(&ddata->lock);
327  return r;
328 }
329 
330 static bool tfp410_detect(struct omap_dss_device *dssdev)
331 {
332  struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
333  unsigned char out;
334  int r;
335 
336  mutex_lock(&ddata->lock);
337 
338  if (!ddata->i2c_adapter)
339  goto out;
340 
341  r = tfp410_ddc_read(ddata->i2c_adapter, &out, 1, 0);
342 
343  mutex_unlock(&ddata->lock);
344 
345  return r == 0;
346 
347 out:
348  mutex_unlock(&ddata->lock);
349  return true;
350 }
351 
352 static struct omap_dss_driver tfp410_driver = {
353  .probe = tfp410_probe,
354  .remove = __exit_p(tfp410_remove),
355 
356  .enable = tfp410_enable,
357  .disable = tfp410_disable,
358  .suspend = tfp410_suspend,
359  .resume = tfp410_resume,
360 
361  .set_timings = tfp410_set_timings,
362  .get_timings = tfp410_get_timings,
363  .check_timings = tfp410_check_timings,
364 
365  .read_edid = tfp410_read_edid,
366  .detect = tfp410_detect,
367 
368  .driver = {
369  .name = "tfp410",
370  .owner = THIS_MODULE,
371  },
372 };
373 
374 static int __init tfp410_init(void)
375 {
376  return omap_dss_register_driver(&tfp410_driver);
377 }
378 
379 static void __exit tfp410_exit(void)
380 {
381  omap_dss_unregister_driver(&tfp410_driver);
382 }
383 
384 module_init(tfp410_init);
385 module_exit(tfp410_exit);
386 MODULE_LICENSE("GPL");