diff options
Diffstat (limited to 'drivers/gpu/drm/tilcdc/tilcdc_panel.c')
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_panel.c | 74 |
1 files changed, 57 insertions, 17 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index 4c7aa1d8134f..7a0315855e90 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/pinctrl/pinmux.h> | 18 | #include <linux/pinctrl/pinmux.h> |
19 | #include <linux/pinctrl/consumer.h> | 19 | #include <linux/pinctrl/consumer.h> |
20 | #include <linux/backlight.h> | 20 | #include <linux/backlight.h> |
21 | #include <linux/gpio/consumer.h> | ||
21 | #include <video/display_timing.h> | 22 | #include <video/display_timing.h> |
22 | #include <video/of_display_timing.h> | 23 | #include <video/of_display_timing.h> |
23 | #include <video/videomode.h> | 24 | #include <video/videomode.h> |
@@ -29,6 +30,7 @@ struct panel_module { | |||
29 | struct tilcdc_panel_info *info; | 30 | struct tilcdc_panel_info *info; |
30 | struct display_timings *timings; | 31 | struct display_timings *timings; |
31 | struct backlight_device *backlight; | 32 | struct backlight_device *backlight; |
33 | struct gpio_desc *enable_gpio; | ||
32 | }; | 34 | }; |
33 | #define to_panel_module(x) container_of(x, struct panel_module, base) | 35 | #define to_panel_module(x) container_of(x, struct panel_module, base) |
34 | 36 | ||
@@ -55,13 +57,17 @@ static void panel_encoder_dpms(struct drm_encoder *encoder, int mode) | |||
55 | { | 57 | { |
56 | struct panel_encoder *panel_encoder = to_panel_encoder(encoder); | 58 | struct panel_encoder *panel_encoder = to_panel_encoder(encoder); |
57 | struct backlight_device *backlight = panel_encoder->mod->backlight; | 59 | struct backlight_device *backlight = panel_encoder->mod->backlight; |
60 | struct gpio_desc *gpio = panel_encoder->mod->enable_gpio; | ||
58 | 61 | ||
59 | if (!backlight) | 62 | if (backlight) { |
60 | return; | 63 | backlight->props.power = mode == DRM_MODE_DPMS_ON ? |
64 | FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; | ||
65 | backlight_update_status(backlight); | ||
66 | } | ||
61 | 67 | ||
62 | backlight->props.power = mode == DRM_MODE_DPMS_ON | 68 | if (gpio) |
63 | ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; | 69 | gpiod_set_value_cansleep(gpio, |
64 | backlight_update_status(backlight); | 70 | mode == DRM_MODE_DPMS_ON ? 1 : 0); |
65 | } | 71 | } |
66 | 72 | ||
67 | static bool panel_encoder_mode_fixup(struct drm_encoder *encoder, | 73 | static bool panel_encoder_mode_fixup(struct drm_encoder *encoder, |
@@ -311,6 +317,7 @@ static struct tilcdc_panel_info *of_get_panel_info(struct device_node *np) | |||
311 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 317 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
312 | if (!info) { | 318 | if (!info) { |
313 | pr_err("%s: allocation failed\n", __func__); | 319 | pr_err("%s: allocation failed\n", __func__); |
320 | of_node_put(info_np); | ||
314 | return NULL; | 321 | return NULL; |
315 | } | 322 | } |
316 | 323 | ||
@@ -331,22 +338,21 @@ static struct tilcdc_panel_info *of_get_panel_info(struct device_node *np) | |||
331 | if (ret) { | 338 | if (ret) { |
332 | pr_err("%s: error reading panel-info properties\n", __func__); | 339 | pr_err("%s: error reading panel-info properties\n", __func__); |
333 | kfree(info); | 340 | kfree(info); |
341 | of_node_put(info_np); | ||
334 | return NULL; | 342 | return NULL; |
335 | } | 343 | } |
344 | of_node_put(info_np); | ||
336 | 345 | ||
337 | return info; | 346 | return info; |
338 | } | 347 | } |
339 | 348 | ||
340 | static struct of_device_id panel_of_match[]; | ||
341 | |||
342 | static int panel_probe(struct platform_device *pdev) | 349 | static int panel_probe(struct platform_device *pdev) |
343 | { | 350 | { |
344 | struct device_node *node = pdev->dev.of_node; | 351 | struct device_node *bl_node, *node = pdev->dev.of_node; |
345 | struct panel_module *panel_mod; | 352 | struct panel_module *panel_mod; |
346 | struct tilcdc_module *mod; | 353 | struct tilcdc_module *mod; |
347 | struct pinctrl *pinctrl; | 354 | struct pinctrl *pinctrl; |
348 | int ret = -EINVAL; | 355 | int ret; |
349 | |||
350 | 356 | ||
351 | /* bail out early if no DT data: */ | 357 | /* bail out early if no DT data: */ |
352 | if (!node) { | 358 | if (!node) { |
@@ -354,10 +360,40 @@ static int panel_probe(struct platform_device *pdev) | |||
354 | return -ENXIO; | 360 | return -ENXIO; |
355 | } | 361 | } |
356 | 362 | ||
357 | panel_mod = kzalloc(sizeof(*panel_mod), GFP_KERNEL); | 363 | panel_mod = devm_kzalloc(&pdev->dev, sizeof(*panel_mod), GFP_KERNEL); |
358 | if (!panel_mod) | 364 | if (!panel_mod) |
359 | return -ENOMEM; | 365 | return -ENOMEM; |
360 | 366 | ||
367 | bl_node = of_parse_phandle(node, "backlight", 0); | ||
368 | if (bl_node) { | ||
369 | panel_mod->backlight = of_find_backlight_by_node(bl_node); | ||
370 | of_node_put(bl_node); | ||
371 | |||
372 | if (!panel_mod->backlight) | ||
373 | return -EPROBE_DEFER; | ||
374 | |||
375 | dev_info(&pdev->dev, "found backlight\n"); | ||
376 | } | ||
377 | |||
378 | panel_mod->enable_gpio = devm_gpiod_get(&pdev->dev, "enable"); | ||
379 | if (IS_ERR(panel_mod->enable_gpio)) { | ||
380 | ret = PTR_ERR(panel_mod->enable_gpio); | ||
381 | if (ret != -ENOENT) { | ||
382 | dev_err(&pdev->dev, "failed to request enable GPIO\n"); | ||
383 | goto fail_backlight; | ||
384 | } | ||
385 | |||
386 | /* Optional GPIO is not here, continue silently. */ | ||
387 | panel_mod->enable_gpio = NULL; | ||
388 | } else { | ||
389 | ret = gpiod_direction_output(panel_mod->enable_gpio, 0); | ||
390 | if (ret < 0) { | ||
391 | dev_err(&pdev->dev, "failed to setup GPIO\n"); | ||
392 | goto fail_backlight; | ||
393 | } | ||
394 | dev_info(&pdev->dev, "found enable GPIO\n"); | ||
395 | } | ||
396 | |||
361 | mod = &panel_mod->base; | 397 | mod = &panel_mod->base; |
362 | pdev->dev.platform_data = mod; | 398 | pdev->dev.platform_data = mod; |
363 | 399 | ||
@@ -370,29 +406,30 @@ static int panel_probe(struct platform_device *pdev) | |||
370 | panel_mod->timings = of_get_display_timings(node); | 406 | panel_mod->timings = of_get_display_timings(node); |
371 | if (!panel_mod->timings) { | 407 | if (!panel_mod->timings) { |
372 | dev_err(&pdev->dev, "could not get panel timings\n"); | 408 | dev_err(&pdev->dev, "could not get panel timings\n"); |
409 | ret = -EINVAL; | ||
373 | goto fail_free; | 410 | goto fail_free; |
374 | } | 411 | } |
375 | 412 | ||
376 | panel_mod->info = of_get_panel_info(node); | 413 | panel_mod->info = of_get_panel_info(node); |
377 | if (!panel_mod->info) { | 414 | if (!panel_mod->info) { |
378 | dev_err(&pdev->dev, "could not get panel info\n"); | 415 | dev_err(&pdev->dev, "could not get panel info\n"); |
416 | ret = -EINVAL; | ||
379 | goto fail_timings; | 417 | goto fail_timings; |
380 | } | 418 | } |
381 | 419 | ||
382 | mod->preferred_bpp = panel_mod->info->bpp; | 420 | mod->preferred_bpp = panel_mod->info->bpp; |
383 | 421 | ||
384 | panel_mod->backlight = of_find_backlight_by_node(node); | ||
385 | if (panel_mod->backlight) | ||
386 | dev_info(&pdev->dev, "found backlight\n"); | ||
387 | |||
388 | return 0; | 422 | return 0; |
389 | 423 | ||
390 | fail_timings: | 424 | fail_timings: |
391 | display_timings_release(panel_mod->timings); | 425 | display_timings_release(panel_mod->timings); |
392 | 426 | ||
393 | fail_free: | 427 | fail_free: |
394 | kfree(panel_mod); | ||
395 | tilcdc_module_cleanup(mod); | 428 | tilcdc_module_cleanup(mod); |
429 | |||
430 | fail_backlight: | ||
431 | if (panel_mod->backlight) | ||
432 | put_device(&panel_mod->backlight->dev); | ||
396 | return ret; | 433 | return ret; |
397 | } | 434 | } |
398 | 435 | ||
@@ -400,12 +437,15 @@ static int panel_remove(struct platform_device *pdev) | |||
400 | { | 437 | { |
401 | struct tilcdc_module *mod = dev_get_platdata(&pdev->dev); | 438 | struct tilcdc_module *mod = dev_get_platdata(&pdev->dev); |
402 | struct panel_module *panel_mod = to_panel_module(mod); | 439 | struct panel_module *panel_mod = to_panel_module(mod); |
440 | struct backlight_device *backlight = panel_mod->backlight; | ||
441 | |||
442 | if (backlight) | ||
443 | put_device(&backlight->dev); | ||
403 | 444 | ||
404 | display_timings_release(panel_mod->timings); | 445 | display_timings_release(panel_mod->timings); |
405 | 446 | ||
406 | tilcdc_module_cleanup(mod); | 447 | tilcdc_module_cleanup(mod); |
407 | kfree(panel_mod->info); | 448 | kfree(panel_mod->info); |
408 | kfree(panel_mod); | ||
409 | 449 | ||
410 | return 0; | 450 | return 0; |
411 | } | 451 | } |