aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tegra/dpaux.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/tegra/dpaux.c')
-rw-r--r--drivers/gpu/drm/tegra/dpaux.c245
1 files changed, 202 insertions, 43 deletions
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
index b24a0f14821a..059f409556d5 100644
--- a/drivers/gpu/drm/tegra/dpaux.c
+++ b/drivers/gpu/drm/tegra/dpaux.c
@@ -12,6 +12,9 @@
12#include <linux/interrupt.h> 12#include <linux/interrupt.h>
13#include <linux/io.h> 13#include <linux/io.h>
14#include <linux/of_gpio.h> 14#include <linux/of_gpio.h>
15#include <linux/pinctrl/pinconf-generic.h>
16#include <linux/pinctrl/pinctrl.h>
17#include <linux/pinctrl/pinmux.h>
15#include <linux/platform_device.h> 18#include <linux/platform_device.h>
16#include <linux/reset.h> 19#include <linux/reset.h>
17#include <linux/regulator/consumer.h> 20#include <linux/regulator/consumer.h>
@@ -44,6 +47,11 @@ struct tegra_dpaux {
44 struct completion complete; 47 struct completion complete;
45 struct work_struct work; 48 struct work_struct work;
46 struct list_head list; 49 struct list_head list;
50
51#ifdef CONFIG_GENERIC_PINCONF
52 struct pinctrl_dev *pinctrl;
53 struct pinctrl_desc desc;
54#endif
47}; 55};
48 56
49static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux) 57static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux)
@@ -267,6 +275,148 @@ static irqreturn_t tegra_dpaux_irq(int irq, void *data)
267 return ret; 275 return ret;
268} 276}
269 277
278enum tegra_dpaux_functions {
279 DPAUX_PADCTL_FUNC_AUX,
280 DPAUX_PADCTL_FUNC_I2C,
281 DPAUX_PADCTL_FUNC_OFF,
282};
283
284static void tegra_dpaux_pad_power_down(struct tegra_dpaux *dpaux)
285{
286 u32 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
287
288 value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
289
290 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
291}
292
293static void tegra_dpaux_pad_power_up(struct tegra_dpaux *dpaux)
294{
295 u32 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
296
297 value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
298
299 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
300}
301
302static int tegra_dpaux_pad_config(struct tegra_dpaux *dpaux, unsigned function)
303{
304 u32 value;
305
306 switch (function) {
307 case DPAUX_PADCTL_FUNC_AUX:
308 value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) |
309 DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) |
310 DPAUX_HYBRID_PADCTL_AUX_DRVI(0x18) |
311 DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV |
312 DPAUX_HYBRID_PADCTL_MODE_AUX;
313 break;
314
315 case DPAUX_PADCTL_FUNC_I2C:
316 value = DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV |
317 DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV |
318 DPAUX_HYBRID_PADCTL_MODE_I2C;
319 break;
320
321 case DPAUX_PADCTL_FUNC_OFF:
322 tegra_dpaux_pad_power_down(dpaux);
323 return 0;
324
325 default:
326 return -ENOTSUPP;
327 }
328
329 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL);
330 tegra_dpaux_pad_power_up(dpaux);
331
332 return 0;
333}
334
335#ifdef CONFIG_GENERIC_PINCONF
336static const struct pinctrl_pin_desc tegra_dpaux_pins[] = {
337 PINCTRL_PIN(0, "DP_AUX_CHx_P"),
338 PINCTRL_PIN(1, "DP_AUX_CHx_N"),
339};
340
341static const unsigned tegra_dpaux_pin_numbers[] = { 0, 1 };
342
343static const char * const tegra_dpaux_groups[] = {
344 "dpaux-io",
345};
346
347static const char * const tegra_dpaux_functions[] = {
348 "aux",
349 "i2c",
350 "off",
351};
352
353static int tegra_dpaux_get_groups_count(struct pinctrl_dev *pinctrl)
354{
355 return ARRAY_SIZE(tegra_dpaux_groups);
356}
357
358static const char *tegra_dpaux_get_group_name(struct pinctrl_dev *pinctrl,
359 unsigned int group)
360{
361 return tegra_dpaux_groups[group];
362}
363
364static int tegra_dpaux_get_group_pins(struct pinctrl_dev *pinctrl,
365 unsigned group, const unsigned **pins,
366 unsigned *num_pins)
367{
368 *pins = tegra_dpaux_pin_numbers;
369 *num_pins = ARRAY_SIZE(tegra_dpaux_pin_numbers);
370
371 return 0;
372}
373
374static const struct pinctrl_ops tegra_dpaux_pinctrl_ops = {
375 .get_groups_count = tegra_dpaux_get_groups_count,
376 .get_group_name = tegra_dpaux_get_group_name,
377 .get_group_pins = tegra_dpaux_get_group_pins,
378 .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
379 .dt_free_map = pinconf_generic_dt_free_map,
380};
381
382static int tegra_dpaux_get_functions_count(struct pinctrl_dev *pinctrl)
383{
384 return ARRAY_SIZE(tegra_dpaux_functions);
385}
386
387static const char *tegra_dpaux_get_function_name(struct pinctrl_dev *pinctrl,
388 unsigned int function)
389{
390 return tegra_dpaux_functions[function];
391}
392
393static int tegra_dpaux_get_function_groups(struct pinctrl_dev *pinctrl,
394 unsigned int function,
395 const char * const **groups,
396 unsigned * const num_groups)
397{
398 *num_groups = ARRAY_SIZE(tegra_dpaux_groups);
399 *groups = tegra_dpaux_groups;
400
401 return 0;
402}
403
404static int tegra_dpaux_set_mux(struct pinctrl_dev *pinctrl,
405 unsigned int function, unsigned int group)
406{
407 struct tegra_dpaux *dpaux = pinctrl_dev_get_drvdata(pinctrl);
408
409 return tegra_dpaux_pad_config(dpaux, function);
410}
411
412static const struct pinmux_ops tegra_dpaux_pinmux_ops = {
413 .get_functions_count = tegra_dpaux_get_functions_count,
414 .get_function_name = tegra_dpaux_get_function_name,
415 .get_function_groups = tegra_dpaux_get_function_groups,
416 .set_mux = tegra_dpaux_set_mux,
417};
418#endif
419
270static int tegra_dpaux_probe(struct platform_device *pdev) 420static int tegra_dpaux_probe(struct platform_device *pdev)
271{ 421{
272 struct tegra_dpaux *dpaux; 422 struct tegra_dpaux *dpaux;
@@ -294,11 +444,14 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
294 return -ENXIO; 444 return -ENXIO;
295 } 445 }
296 446
297 dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux"); 447 if (!pdev->dev.pm_domain) {
298 if (IS_ERR(dpaux->rst)) { 448 dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux");
299 dev_err(&pdev->dev, "failed to get reset control: %ld\n", 449 if (IS_ERR(dpaux->rst)) {
300 PTR_ERR(dpaux->rst)); 450 dev_err(&pdev->dev,
301 return PTR_ERR(dpaux->rst); 451 "failed to get reset control: %ld\n",
452 PTR_ERR(dpaux->rst));
453 return PTR_ERR(dpaux->rst);
454 }
302 } 455 }
303 456
304 dpaux->clk = devm_clk_get(&pdev->dev, NULL); 457 dpaux->clk = devm_clk_get(&pdev->dev, NULL);
@@ -315,34 +468,37 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
315 return err; 468 return err;
316 } 469 }
317 470
318 reset_control_deassert(dpaux->rst); 471 if (dpaux->rst)
472 reset_control_deassert(dpaux->rst);
319 473
320 dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent"); 474 dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent");
321 if (IS_ERR(dpaux->clk_parent)) { 475 if (IS_ERR(dpaux->clk_parent)) {
322 dev_err(&pdev->dev, "failed to get parent clock: %ld\n", 476 dev_err(&pdev->dev, "failed to get parent clock: %ld\n",
323 PTR_ERR(dpaux->clk_parent)); 477 PTR_ERR(dpaux->clk_parent));
324 return PTR_ERR(dpaux->clk_parent); 478 err = PTR_ERR(dpaux->clk_parent);
479 goto assert_reset;
325 } 480 }
326 481
327 err = clk_prepare_enable(dpaux->clk_parent); 482 err = clk_prepare_enable(dpaux->clk_parent);
328 if (err < 0) { 483 if (err < 0) {
329 dev_err(&pdev->dev, "failed to enable parent clock: %d\n", 484 dev_err(&pdev->dev, "failed to enable parent clock: %d\n",
330 err); 485 err);
331 return err; 486 goto assert_reset;
332 } 487 }
333 488
334 err = clk_set_rate(dpaux->clk_parent, 270000000); 489 err = clk_set_rate(dpaux->clk_parent, 270000000);
335 if (err < 0) { 490 if (err < 0) {
336 dev_err(&pdev->dev, "failed to set clock to 270 MHz: %d\n", 491 dev_err(&pdev->dev, "failed to set clock to 270 MHz: %d\n",
337 err); 492 err);
338 return err; 493 goto disable_parent_clk;
339 } 494 }
340 495
341 dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd"); 496 dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd");
342 if (IS_ERR(dpaux->vdd)) { 497 if (IS_ERR(dpaux->vdd)) {
343 dev_err(&pdev->dev, "failed to get VDD supply: %ld\n", 498 dev_err(&pdev->dev, "failed to get VDD supply: %ld\n",
344 PTR_ERR(dpaux->vdd)); 499 PTR_ERR(dpaux->vdd));
345 return PTR_ERR(dpaux->vdd); 500 err = PTR_ERR(dpaux->vdd);
501 goto disable_parent_clk;
346 } 502 }
347 503
348 err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0, 504 err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0,
@@ -350,7 +506,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
350 if (err < 0) { 506 if (err < 0) {
351 dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n", 507 dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n",
352 dpaux->irq, err); 508 dpaux->irq, err);
353 return err; 509 goto disable_parent_clk;
354 } 510 }
355 511
356 disable_irq(dpaux->irq); 512 disable_irq(dpaux->irq);
@@ -360,7 +516,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
360 516
361 err = drm_dp_aux_register(&dpaux->aux); 517 err = drm_dp_aux_register(&dpaux->aux);
362 if (err < 0) 518 if (err < 0)
363 return err; 519 goto disable_parent_clk;
364 520
365 /* 521 /*
366 * Assume that by default the DPAUX/I2C pads will be used for HDMI, 522 * Assume that by default the DPAUX/I2C pads will be used for HDMI,
@@ -370,16 +526,24 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
370 * is no possibility to perform the I2C mode configuration in the 526 * is no possibility to perform the I2C mode configuration in the
371 * HDMI path. 527 * HDMI path.
372 */ 528 */
373 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); 529 err = tegra_dpaux_pad_config(dpaux, DPAUX_HYBRID_PADCTL_MODE_I2C);
374 value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; 530 if (err < 0)
375 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); 531 return err;
376
377 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_PADCTL);
378 value = DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV |
379 DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV |
380 DPAUX_HYBRID_PADCTL_MODE_I2C;
381 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL);
382 532
533#ifdef CONFIG_GENERIC_PINCONF
534 dpaux->desc.name = dev_name(&pdev->dev);
535 dpaux->desc.pins = tegra_dpaux_pins;
536 dpaux->desc.npins = ARRAY_SIZE(tegra_dpaux_pins);
537 dpaux->desc.pctlops = &tegra_dpaux_pinctrl_ops;
538 dpaux->desc.pmxops = &tegra_dpaux_pinmux_ops;
539 dpaux->desc.owner = THIS_MODULE;
540
541 dpaux->pinctrl = devm_pinctrl_register(&pdev->dev, &dpaux->desc, dpaux);
542 if (!dpaux->pinctrl) {
543 dev_err(&pdev->dev, "failed to register pincontrol\n");
544 return -ENODEV;
545 }
546#endif
383 /* enable and clear all interrupts */ 547 /* enable and clear all interrupts */
384 value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT | 548 value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT |
385 DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT; 549 DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT;
@@ -393,17 +557,24 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
393 platform_set_drvdata(pdev, dpaux); 557 platform_set_drvdata(pdev, dpaux);
394 558
395 return 0; 559 return 0;
560
561disable_parent_clk:
562 clk_disable_unprepare(dpaux->clk_parent);
563assert_reset:
564 if (dpaux->rst)
565 reset_control_assert(dpaux->rst);
566
567 clk_disable_unprepare(dpaux->clk);
568
569 return err;
396} 570}
397 571
398static int tegra_dpaux_remove(struct platform_device *pdev) 572static int tegra_dpaux_remove(struct platform_device *pdev)
399{ 573{
400 struct tegra_dpaux *dpaux = platform_get_drvdata(pdev); 574 struct tegra_dpaux *dpaux = platform_get_drvdata(pdev);
401 u32 value;
402 575
403 /* make sure pads are powered down when not in use */ 576 /* make sure pads are powered down when not in use */
404 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); 577 tegra_dpaux_pad_power_down(dpaux);
405 value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
406 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
407 578
408 drm_dp_aux_unregister(&dpaux->aux); 579 drm_dp_aux_unregister(&dpaux->aux);
409 580
@@ -414,7 +585,10 @@ static int tegra_dpaux_remove(struct platform_device *pdev)
414 cancel_work_sync(&dpaux->work); 585 cancel_work_sync(&dpaux->work);
415 586
416 clk_disable_unprepare(dpaux->clk_parent); 587 clk_disable_unprepare(dpaux->clk_parent);
417 reset_control_assert(dpaux->rst); 588
589 if (dpaux->rst)
590 reset_control_assert(dpaux->rst);
591
418 clk_disable_unprepare(dpaux->clk); 592 clk_disable_unprepare(dpaux->clk);
419 593
420 return 0; 594 return 0;
@@ -528,30 +702,15 @@ enum drm_connector_status drm_dp_aux_detect(struct drm_dp_aux *aux)
528int drm_dp_aux_enable(struct drm_dp_aux *aux) 702int drm_dp_aux_enable(struct drm_dp_aux *aux)
529{ 703{
530 struct tegra_dpaux *dpaux = to_dpaux(aux); 704 struct tegra_dpaux *dpaux = to_dpaux(aux);
531 u32 value;
532
533 value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) |
534 DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) |
535 DPAUX_HYBRID_PADCTL_AUX_DRVI(0x18) |
536 DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV |
537 DPAUX_HYBRID_PADCTL_MODE_AUX;
538 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL);
539
540 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
541 value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
542 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
543 705
544 return 0; 706 return tegra_dpaux_pad_config(dpaux, DPAUX_PADCTL_FUNC_AUX);
545} 707}
546 708
547int drm_dp_aux_disable(struct drm_dp_aux *aux) 709int drm_dp_aux_disable(struct drm_dp_aux *aux)
548{ 710{
549 struct tegra_dpaux *dpaux = to_dpaux(aux); 711 struct tegra_dpaux *dpaux = to_dpaux(aux);
550 u32 value;
551 712
552 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); 713 tegra_dpaux_pad_power_down(dpaux);
553 value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
554 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
555 714
556 return 0; 715 return 0;
557} 716}