blob: 998f0df199115e42e18e405397ed5e85d49f1094 [file] [log] [blame]
Svyatoslav Ryhel4c717fb2023-04-25 10:51:46 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
4 */
5
6#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
7
8#include <backlight.h>
Svyatoslav Ryhel4c717fb2023-04-25 10:51:46 +03009#include <dm.h>
10#include <i2c.h>
11#include <log.h>
12#include <linux/delay.h>
13#include <linux/err.h>
14
15#include <asm/io.h>
16#include <asm/gpio.h>
Svyatoslav Ryhel75fec412024-01-23 19:16:18 +020017
18#include "tegra-dc.h"
Svyatoslav Ryhel4c717fb2023-04-25 10:51:46 +030019
Svyatoslav Ryhel4c717fb2023-04-25 10:51:46 +030020#define TEGRA_PWM_BL_MIN_BRIGHTNESS 0x10
21#define TEGRA_PWM_BL_MAX_BRIGHTNESS 0xFF
22
23#define TEGRA_PWM_BL_PERIOD 0xFF
24#define TEGRA_PWM_BL_CLK_DIV 0x14
25#define TEGRA_PWM_BL_CLK_SELECT 0x00
26
27#define PM_PERIOD_SHIFT 18
28#define PM_CLK_DIVIDER_SHIFT 4
29
30#define TEGRA_PWM_PM0 0
31#define TEGRA_PWM_PM1 1
32
33struct tegra_pwm_backlight_priv {
34 struct dc_ctlr *dc; /* Display controller regmap */
35
36 u32 pwm_source;
37 u32 period;
38 u32 clk_div;
39 u32 clk_select;
40 u32 dft_brightness;
41};
42
43static int tegra_pwm_backlight_set_brightness(struct udevice *dev, int percent)
44{
45 struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
46 struct dc_cmd_reg *cmd = &priv->dc->cmd;
47 struct dc_com_reg *com = &priv->dc->com;
48 unsigned int ctrl;
49 unsigned long out_sel;
50 unsigned long cmd_state;
51
52 if (percent == BACKLIGHT_DEFAULT)
53 percent = priv->dft_brightness;
54
55 if (percent < TEGRA_PWM_BL_MIN_BRIGHTNESS)
56 percent = TEGRA_PWM_BL_MIN_BRIGHTNESS;
57
58 if (percent > TEGRA_PWM_BL_MAX_BRIGHTNESS)
59 percent = TEGRA_PWM_BL_MAX_BRIGHTNESS;
60
61 ctrl = ((priv->period << PM_PERIOD_SHIFT) |
62 (priv->clk_div << PM_CLK_DIVIDER_SHIFT) |
63 priv->clk_select);
64
65 /* The new value should be effected immediately */
66 cmd_state = readl(&cmd->state_access);
67 writel((cmd_state | (1 << 2)), &cmd->state_access);
68
69 switch (priv->pwm_source) {
70 case TEGRA_PWM_PM0:
71 /* Select the LM0 on PM0 */
72 out_sel = readl(&com->pin_output_sel[5]);
73 out_sel &= ~(7 << 0);
74 out_sel |= (3 << 0);
75 writel(out_sel, &com->pin_output_sel[5]);
76 writel(ctrl, &com->pm0_ctrl);
77 writel(percent, &com->pm0_duty_cycle);
78 break;
79 case TEGRA_PWM_PM1:
80 /* Select the LM1 on PM1 */
81 out_sel = readl(&com->pin_output_sel[5]);
82 out_sel &= ~(7 << 4);
83 out_sel |= (3 << 4);
84 writel(out_sel, &com->pin_output_sel[5]);
85 writel(ctrl, &com->pm1_ctrl);
86 writel(percent, &com->pm1_duty_cycle);
87 break;
88 default:
89 break;
90 }
91
92 writel(cmd_state, &cmd->state_access);
93 return 0;
94}
95
96static int tegra_pwm_backlight_enable(struct udevice *dev)
97{
98 struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
99
100 return tegra_pwm_backlight_set_brightness(dev, priv->dft_brightness);
101}
102
103static int tegra_pwm_backlight_probe(struct udevice *dev)
104{
105 struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
Svyatoslav Ryhelc14e3a62025-03-01 14:45:04 +0200106 ofnode dc = ofnode_get_parent(dev_ofnode(dev));
Svyatoslav Ryhel4c717fb2023-04-25 10:51:46 +0300107
Svyatoslav Ryhelc14e3a62025-03-01 14:45:04 +0200108 priv->dc = (struct dc_ctlr *)ofnode_get_addr(dc);
Svyatoslav Ryhel4c717fb2023-04-25 10:51:46 +0300109 if (!priv->dc) {
Svyatoslav Ryhelc14e3a62025-03-01 14:45:04 +0200110 log_err("%s: failed to get DC controller\n", __func__);
Svyatoslav Ryhel4c717fb2023-04-25 10:51:46 +0300111 return -EINVAL;
112 }
113
114 priv->pwm_source =
115 dev_read_u32_default(dev, "nvidia,pwm-source",
116 TEGRA_PWM_PM0);
117 priv->period =
118 dev_read_u32_default(dev, "nvidia,period",
119 TEGRA_PWM_BL_PERIOD);
120 priv->clk_div =
121 dev_read_u32_default(dev, "nvidia,clock-div",
122 TEGRA_PWM_BL_CLK_DIV);
123 priv->clk_select =
124 dev_read_u32_default(dev, "nvidia,clock-select",
125 TEGRA_PWM_BL_CLK_SELECT);
126 priv->dft_brightness =
127 dev_read_u32_default(dev, "nvidia,default-brightness",
128 TEGRA_PWM_BL_MAX_BRIGHTNESS);
129
130 return 0;
131}
132
133static const struct backlight_ops tegra_pwm_backlight_ops = {
134 .enable = tegra_pwm_backlight_enable,
135 .set_brightness = tegra_pwm_backlight_set_brightness,
136};
137
138static const struct udevice_id tegra_pwm_backlight_ids[] = {
139 { .compatible = "nvidia,tegra-pwm-backlight" },
140 { }
141};
142
143U_BOOT_DRIVER(tegra_pwm_backlight) = {
144 .name = "tegra_pwm_backlight",
145 .id = UCLASS_PANEL_BACKLIGHT,
146 .of_match = tegra_pwm_backlight_ids,
147 .probe = tegra_pwm_backlight_probe,
148 .ops = &tegra_pwm_backlight_ops,
149 .priv_auto = sizeof(struct tegra_pwm_backlight_priv),
150};