| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * i.MX drm driver - Television Encoder (TVEv2) |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2013 Philipp Zabel, Pengutronix |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License |
|---|
| 8 | | - * as published by the Free Software Foundation; either version 2 |
|---|
| 9 | | - * of the License, or (at your option) any later version. |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | 6 | */ |
|---|
| 15 | 7 | |
|---|
| 16 | | -#include <linux/clk.h> |
|---|
| 17 | 8 | #include <linux/clk-provider.h> |
|---|
| 9 | +#include <linux/clk.h> |
|---|
| 18 | 10 | #include <linux/component.h> |
|---|
| 19 | | -#include <linux/module.h> |
|---|
| 20 | 11 | #include <linux/i2c.h> |
|---|
| 12 | +#include <linux/module.h> |
|---|
| 13 | +#include <linux/platform_device.h> |
|---|
| 21 | 14 | #include <linux/regmap.h> |
|---|
| 22 | 15 | #include <linux/regulator/consumer.h> |
|---|
| 23 | | -#include <linux/spinlock.h> |
|---|
| 24 | 16 | #include <linux/videodev2.h> |
|---|
| 25 | | -#include <drm/drmP.h> |
|---|
| 17 | + |
|---|
| 18 | +#include <video/imx-ipu-v3.h> |
|---|
| 19 | + |
|---|
| 26 | 20 | #include <drm/drm_atomic_helper.h> |
|---|
| 27 | 21 | #include <drm/drm_fb_helper.h> |
|---|
| 28 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 29 | | -#include <video/imx-ipu-v3.h> |
|---|
| 22 | +#include <drm/drm_probe_helper.h> |
|---|
| 23 | +#include <drm/drm_simple_kms_helper.h> |
|---|
| 30 | 24 | |
|---|
| 31 | 25 | #include "imx-drm.h" |
|---|
| 32 | 26 | |
|---|
| .. | .. |
|---|
| 109 | 103 | struct drm_connector connector; |
|---|
| 110 | 104 | struct drm_encoder encoder; |
|---|
| 111 | 105 | struct device *dev; |
|---|
| 112 | | - spinlock_t lock; /* register lock */ |
|---|
| 113 | | - bool enabled; |
|---|
| 114 | 106 | int mode; |
|---|
| 115 | 107 | int di_hsync_pin; |
|---|
| 116 | 108 | int di_vsync_pin; |
|---|
| .. | .. |
|---|
| 134 | 126 | return container_of(e, struct imx_tve, encoder); |
|---|
| 135 | 127 | } |
|---|
| 136 | 128 | |
|---|
| 137 | | -static void tve_lock(void *__tve) |
|---|
| 138 | | -__acquires(&tve->lock) |
|---|
| 139 | | -{ |
|---|
| 140 | | - struct imx_tve *tve = __tve; |
|---|
| 141 | | - |
|---|
| 142 | | - spin_lock(&tve->lock); |
|---|
| 143 | | -} |
|---|
| 144 | | - |
|---|
| 145 | | -static void tve_unlock(void *__tve) |
|---|
| 146 | | -__releases(&tve->lock) |
|---|
| 147 | | -{ |
|---|
| 148 | | - struct imx_tve *tve = __tve; |
|---|
| 149 | | - |
|---|
| 150 | | - spin_unlock(&tve->lock); |
|---|
| 151 | | -} |
|---|
| 152 | | - |
|---|
| 153 | 129 | static void tve_enable(struct imx_tve *tve) |
|---|
| 154 | 130 | { |
|---|
| 155 | | - if (!tve->enabled) { |
|---|
| 156 | | - tve->enabled = true; |
|---|
| 157 | | - clk_prepare_enable(tve->clk); |
|---|
| 158 | | - regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, |
|---|
| 159 | | - TVE_EN, TVE_EN); |
|---|
| 160 | | - } |
|---|
| 131 | + clk_prepare_enable(tve->clk); |
|---|
| 132 | + regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, TVE_EN, TVE_EN); |
|---|
| 161 | 133 | |
|---|
| 162 | 134 | /* clear interrupt status register */ |
|---|
| 163 | 135 | regmap_write(tve->regmap, TVE_STAT_REG, 0xffffffff); |
|---|
| .. | .. |
|---|
| 174 | 146 | |
|---|
| 175 | 147 | static void tve_disable(struct imx_tve *tve) |
|---|
| 176 | 148 | { |
|---|
| 177 | | - if (tve->enabled) { |
|---|
| 178 | | - tve->enabled = false; |
|---|
| 179 | | - regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, TVE_EN, 0); |
|---|
| 180 | | - clk_disable_unprepare(tve->clk); |
|---|
| 181 | | - } |
|---|
| 149 | + regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, TVE_EN, 0); |
|---|
| 150 | + clk_disable_unprepare(tve->clk); |
|---|
| 182 | 151 | } |
|---|
| 183 | 152 | |
|---|
| 184 | 153 | static int tve_setup_tvout(struct imx_tve *tve) |
|---|
| .. | .. |
|---|
| 243 | 212 | return ret; |
|---|
| 244 | 213 | } |
|---|
| 245 | 214 | |
|---|
| 246 | | -static int imx_tve_connector_mode_valid(struct drm_connector *connector, |
|---|
| 247 | | - struct drm_display_mode *mode) |
|---|
| 215 | +static enum drm_mode_status |
|---|
| 216 | +imx_tve_connector_mode_valid(struct drm_connector *connector, |
|---|
| 217 | + struct drm_display_mode *mode) |
|---|
| 248 | 218 | { |
|---|
| 249 | 219 | struct imx_tve *tve = con_to_tve(connector); |
|---|
| 250 | 220 | unsigned long rate; |
|---|
| .. | .. |
|---|
| 263 | 233 | mode->hdisplay, mode->vdisplay); |
|---|
| 264 | 234 | |
|---|
| 265 | 235 | return MODE_BAD; |
|---|
| 266 | | -} |
|---|
| 267 | | - |
|---|
| 268 | | -static struct drm_encoder *imx_tve_connector_best_encoder( |
|---|
| 269 | | - struct drm_connector *connector) |
|---|
| 270 | | -{ |
|---|
| 271 | | - struct imx_tve *tve = con_to_tve(connector); |
|---|
| 272 | | - |
|---|
| 273 | | - return &tve->encoder; |
|---|
| 274 | 236 | } |
|---|
| 275 | 237 | |
|---|
| 276 | 238 | static void imx_tve_encoder_mode_set(struct drm_encoder *encoder, |
|---|
| .. | .. |
|---|
| 350 | 312 | |
|---|
| 351 | 313 | static const struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = { |
|---|
| 352 | 314 | .get_modes = imx_tve_connector_get_modes, |
|---|
| 353 | | - .best_encoder = imx_tve_connector_best_encoder, |
|---|
| 354 | 315 | .mode_valid = imx_tve_connector_mode_valid, |
|---|
| 355 | | -}; |
|---|
| 356 | | - |
|---|
| 357 | | -static const struct drm_encoder_funcs imx_tve_encoder_funcs = { |
|---|
| 358 | | - .destroy = imx_drm_encoder_destroy, |
|---|
| 359 | 316 | }; |
|---|
| 360 | 317 | |
|---|
| 361 | 318 | static const struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = { |
|---|
| .. | .. |
|---|
| 442 | 399 | return 0; |
|---|
| 443 | 400 | } |
|---|
| 444 | 401 | |
|---|
| 445 | | -static struct clk_ops clk_tve_di_ops = { |
|---|
| 402 | +static const struct clk_ops clk_tve_di_ops = { |
|---|
| 446 | 403 | .round_rate = clk_tve_di_round_rate, |
|---|
| 447 | 404 | .set_rate = clk_tve_di_set_rate, |
|---|
| 448 | 405 | .recalc_rate = clk_tve_di_recalc_rate, |
|---|
| .. | .. |
|---|
| 485 | 442 | return ret; |
|---|
| 486 | 443 | |
|---|
| 487 | 444 | drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs); |
|---|
| 488 | | - drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs, |
|---|
| 489 | | - encoder_type, NULL); |
|---|
| 445 | + drm_simple_encoder_init(drm, &tve->encoder, encoder_type); |
|---|
| 490 | 446 | |
|---|
| 491 | 447 | drm_connector_helper_add(&tve->connector, |
|---|
| 492 | 448 | &imx_tve_connector_helper_funcs); |
|---|
| 493 | | - drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs, |
|---|
| 494 | | - DRM_MODE_CONNECTOR_VGA); |
|---|
| 449 | + drm_connector_init_with_ddc(drm, &tve->connector, |
|---|
| 450 | + &imx_tve_connector_funcs, |
|---|
| 451 | + DRM_MODE_CONNECTOR_VGA, |
|---|
| 452 | + tve->ddc); |
|---|
| 495 | 453 | |
|---|
| 496 | 454 | drm_connector_attach_encoder(&tve->connector, &tve->encoder); |
|---|
| 497 | 455 | |
|---|
| .. | .. |
|---|
| 517 | 475 | |
|---|
| 518 | 476 | .readable_reg = imx_tve_readable_reg, |
|---|
| 519 | 477 | |
|---|
| 520 | | - .lock = tve_lock, |
|---|
| 521 | | - .unlock = tve_unlock, |
|---|
| 478 | + .fast_io = true, |
|---|
| 522 | 479 | |
|---|
| 523 | 480 | .max_register = 0xdc, |
|---|
| 524 | 481 | }; |
|---|
| .. | .. |
|---|
| 528 | 485 | [TVE_MODE_VGA] = "vga", |
|---|
| 529 | 486 | }; |
|---|
| 530 | 487 | |
|---|
| 531 | | -static const int of_get_tve_mode(struct device_node *np) |
|---|
| 488 | +static int of_get_tve_mode(struct device_node *np) |
|---|
| 532 | 489 | { |
|---|
| 533 | 490 | const char *bm; |
|---|
| 534 | 491 | int ret, i; |
|---|
| .. | .. |
|---|
| 557 | 514 | int irq; |
|---|
| 558 | 515 | int ret; |
|---|
| 559 | 516 | |
|---|
| 560 | | - tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL); |
|---|
| 561 | | - if (!tve) |
|---|
| 562 | | - return -ENOMEM; |
|---|
| 517 | + tve = dev_get_drvdata(dev); |
|---|
| 518 | + memset(tve, 0, sizeof(*tve)); |
|---|
| 563 | 519 | |
|---|
| 564 | 520 | tve->dev = dev; |
|---|
| 565 | | - spin_lock_init(&tve->lock); |
|---|
| 566 | 521 | |
|---|
| 567 | 522 | ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); |
|---|
| 568 | 523 | if (ddc_node) { |
|---|
| .. | .. |
|---|
| 609 | 564 | } |
|---|
| 610 | 565 | |
|---|
| 611 | 566 | irq = platform_get_irq(pdev, 0); |
|---|
| 612 | | - if (irq < 0) { |
|---|
| 613 | | - dev_err(dev, "failed to get irq\n"); |
|---|
| 567 | + if (irq < 0) |
|---|
| 614 | 568 | return irq; |
|---|
| 615 | | - } |
|---|
| 616 | 569 | |
|---|
| 617 | 570 | ret = devm_request_threaded_irq(dev, irq, NULL, |
|---|
| 618 | 571 | imx_tve_irq_handler, IRQF_ONESHOT, |
|---|
| .. | .. |
|---|
| 673 | 626 | if (ret) |
|---|
| 674 | 627 | return ret; |
|---|
| 675 | 628 | |
|---|
| 676 | | - dev_set_drvdata(dev, tve); |
|---|
| 677 | | - |
|---|
| 678 | 629 | return 0; |
|---|
| 679 | 630 | } |
|---|
| 680 | 631 | |
|---|
| .. | .. |
|---|
| 684 | 635 | |
|---|
| 685 | 636 | static int imx_tve_probe(struct platform_device *pdev) |
|---|
| 686 | 637 | { |
|---|
| 638 | + struct imx_tve *tve; |
|---|
| 639 | + |
|---|
| 640 | + tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL); |
|---|
| 641 | + if (!tve) |
|---|
| 642 | + return -ENOMEM; |
|---|
| 643 | + |
|---|
| 644 | + platform_set_drvdata(pdev, tve); |
|---|
| 645 | + |
|---|
| 687 | 646 | return component_add(&pdev->dev, &imx_tve_ops); |
|---|
| 688 | 647 | } |
|---|
| 689 | 648 | |
|---|