]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
video: tegra: add DC based PWM backlight driver
authorSvyatoslav Ryhel <clamor95@gmail.com>
Tue, 25 Apr 2023 07:51:46 +0000 (10:51 +0300)
committerAnatolij Gustschin <agust@denx.de>
Wed, 26 Apr 2023 05:32:25 +0000 (07:32 +0200)
DC based PWM backlight is found on some T20 and T30 devices
(HTC One X). This backlight is controlled by Tegra DC and
is adjustable by the DC PM0 or PM1 signal.

Tested-by: Andreas Westman Dorcsak <hedmoo@yahoo.com> # HTC One X T30
Tested-by: Svyatoslav Ryhel <clamor95@gmail.com> # HTC One X T30
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/video/tegra20/Kconfig
drivers/video/tegra20/Makefile
drivers/video/tegra20/tegra-pwm-backlight.c [new file with mode: 0644]

index 5b1dfbfbbed5bca0ea95ddd241112b207a732f33..f5c4843e11916e77f52a463522ba2a130a8d9666 100644 (file)
@@ -15,3 +15,10 @@ config VIDEO_DSI_TEGRA30
        help
           T30 has native support for DSI panels. This option enables support
           for such panels which can be used on endeavoru and tf600t.
+
+config TEGRA_BACKLIGHT_PWM
+       bool "Enable Tegra DC PWM backlight support"
+       depends on BACKLIGHT
+       select VIDEO_TEGRA20
+       help
+          Tegra DC dependent backlight.
index e82ee96962fa4a1338450945817412623c537935..f0b534c5794324ec454068fd10dc0f477f68011c 100644 (file)
@@ -2,3 +2,4 @@
 
 obj-$(CONFIG_VIDEO_TEGRA20) += tegra-dc.o
 obj-$(CONFIG_VIDEO_DSI_TEGRA30) += tegra-dsi.o mipi-phy.o
+obj-$(CONFIG_TEGRA_BACKLIGHT_PWM) += tegra-pwm-backlight.o
diff --git a/drivers/video/tegra20/tegra-pwm-backlight.c b/drivers/video/tegra20/tegra-pwm-backlight.c
new file mode 100644 (file)
index 0000000..bb677da
--- /dev/null
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
+
+#include <backlight.h>
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/arch/display.h>
+
+#define TEGRA_DISPLAY_A_BASE           0x54200000
+#define TEGRA_DISPLAY_B_BASE           0x54240000
+
+#define TEGRA_PWM_BL_MIN_BRIGHTNESS    0x10
+#define TEGRA_PWM_BL_MAX_BRIGHTNESS    0xFF
+
+#define TEGRA_PWM_BL_PERIOD            0xFF
+#define TEGRA_PWM_BL_CLK_DIV           0x14
+#define TEGRA_PWM_BL_CLK_SELECT                0x00
+
+#define PM_PERIOD_SHIFT                 18
+#define PM_CLK_DIVIDER_SHIFT           4
+
+#define TEGRA_PWM_PM0                  0
+#define TEGRA_PWM_PM1                  1
+
+struct tegra_pwm_backlight_priv {
+       struct dc_ctlr *dc;             /* Display controller regmap */
+
+       u32 pwm_source;
+       u32 period;
+       u32 clk_div;
+       u32 clk_select;
+       u32 dft_brightness;
+};
+
+static int tegra_pwm_backlight_set_brightness(struct udevice *dev, int percent)
+{
+       struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
+       struct dc_cmd_reg *cmd = &priv->dc->cmd;
+       struct dc_com_reg *com = &priv->dc->com;
+       unsigned int ctrl;
+       unsigned long out_sel;
+       unsigned long cmd_state;
+
+       if (percent == BACKLIGHT_DEFAULT)
+               percent = priv->dft_brightness;
+
+       if (percent < TEGRA_PWM_BL_MIN_BRIGHTNESS)
+               percent = TEGRA_PWM_BL_MIN_BRIGHTNESS;
+
+       if (percent > TEGRA_PWM_BL_MAX_BRIGHTNESS)
+               percent = TEGRA_PWM_BL_MAX_BRIGHTNESS;
+
+       ctrl = ((priv->period << PM_PERIOD_SHIFT) |
+               (priv->clk_div << PM_CLK_DIVIDER_SHIFT) |
+                priv->clk_select);
+
+       /* The new value should be effected immediately */
+       cmd_state = readl(&cmd->state_access);
+       writel((cmd_state | (1 << 2)), &cmd->state_access);
+
+       switch (priv->pwm_source) {
+       case TEGRA_PWM_PM0:
+               /* Select the LM0 on PM0 */
+               out_sel = readl(&com->pin_output_sel[5]);
+               out_sel &= ~(7 << 0);
+               out_sel |= (3 << 0);
+               writel(out_sel, &com->pin_output_sel[5]);
+               writel(ctrl, &com->pm0_ctrl);
+               writel(percent, &com->pm0_duty_cycle);
+               break;
+       case TEGRA_PWM_PM1:
+               /* Select the LM1 on PM1 */
+               out_sel = readl(&com->pin_output_sel[5]);
+               out_sel &= ~(7 << 4);
+               out_sel |= (3 << 4);
+               writel(out_sel, &com->pin_output_sel[5]);
+               writel(ctrl, &com->pm1_ctrl);
+               writel(percent, &com->pm1_duty_cycle);
+               break;
+       default:
+               break;
+       }
+
+       writel(cmd_state, &cmd->state_access);
+       return 0;
+}
+
+static int tegra_pwm_backlight_enable(struct udevice *dev)
+{
+       struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
+
+       return tegra_pwm_backlight_set_brightness(dev, priv->dft_brightness);
+}
+
+static int tegra_pwm_backlight_probe(struct udevice *dev)
+{
+       struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
+
+       if (dev_read_bool(dev, "nvidia,display-b-base"))
+               priv->dc = (struct dc_ctlr *)TEGRA_DISPLAY_B_BASE;
+       else
+               priv->dc = (struct dc_ctlr *)TEGRA_DISPLAY_A_BASE;
+
+       if (!priv->dc) {
+               log_err("no display controller address\n");
+               return -EINVAL;
+       }
+
+       priv->pwm_source =
+               dev_read_u32_default(dev, "nvidia,pwm-source",
+                                    TEGRA_PWM_PM0);
+       priv->period =
+               dev_read_u32_default(dev, "nvidia,period",
+                                    TEGRA_PWM_BL_PERIOD);
+       priv->clk_div =
+               dev_read_u32_default(dev, "nvidia,clock-div",
+                                    TEGRA_PWM_BL_CLK_DIV);
+       priv->clk_select =
+               dev_read_u32_default(dev, "nvidia,clock-select",
+                                    TEGRA_PWM_BL_CLK_SELECT);
+       priv->dft_brightness =
+               dev_read_u32_default(dev, "nvidia,default-brightness",
+                                    TEGRA_PWM_BL_MAX_BRIGHTNESS);
+
+       return 0;
+}
+
+static const struct backlight_ops tegra_pwm_backlight_ops = {
+       .enable = tegra_pwm_backlight_enable,
+       .set_brightness = tegra_pwm_backlight_set_brightness,
+};
+
+static const struct udevice_id tegra_pwm_backlight_ids[] = {
+       { .compatible = "nvidia,tegra-pwm-backlight" },
+       { }
+};
+
+U_BOOT_DRIVER(tegra_pwm_backlight) = {
+       .name           = "tegra_pwm_backlight",
+       .id             = UCLASS_PANEL_BACKLIGHT,
+       .of_match       = tegra_pwm_backlight_ids,
+       .probe          = tegra_pwm_backlight_probe,
+       .ops            = &tegra_pwm_backlight_ops,
+       .priv_auto      = sizeof(struct tegra_pwm_backlight_priv),
+};