bcm27xx: add support for linux v5.15
[openwrt/staging/chunkeey.git] / target / linux / bcm27xx / patches-5.15 / 950-0484-regulator-rpi-panel-Convert-to-drive-lines-directly.patch
1 From 3cf717e1b077749001602a141dcdc2151e8307e1 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Thu, 9 Sep 2021 18:24:57 +0100
4 Subject: [PATCH] regulator: rpi-panel: Convert to drive lines directly
5
6 The Atmel was doing a load of automatic sequencing of
7 control lines, however it was combining the touch controller's
8 reset with the bridge/panel control.
9
10 Change to control the control signals directly rather than
11 through the automatic POWERON control.
12
13 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
14 ---
15 .../regulator/rpi-panel-attiny-regulator.c | 111 ++++++++++--------
16 1 file changed, 60 insertions(+), 51 deletions(-)
17
18 --- a/drivers/regulator/rpi-panel-attiny-regulator.c
19 +++ b/drivers/regulator/rpi-panel-attiny-regulator.c
20 @@ -21,11 +21,28 @@
21 /* I2C registers of the Atmel microcontroller. */
22 #define REG_ID 0x80
23 #define REG_PORTA 0x81
24 -#define REG_PORTA_HF BIT(2)
25 -#define REG_PORTA_VF BIT(3)
26 #define REG_PORTB 0x82
27 +#define REG_PORTC 0x83
28 #define REG_POWERON 0x85
29 #define REG_PWM 0x86
30 +#define REG_ADDR_L 0x8c
31 +#define REG_ADDR_H 0x8d
32 +#define REG_WRITE_DATA_H 0x90
33 +#define REG_WRITE_DATA_L 0x91
34 +
35 +#define PA_LCD_DITHB BIT(0)
36 +#define PA_LCD_MODE BIT(1)
37 +#define PA_LCD_LR BIT(2)
38 +#define PA_LCD_UD BIT(3)
39 +
40 +#define PB_BRIDGE_PWRDNX_N BIT(0)
41 +#define PB_LCD_VCC_N BIT(1)
42 +#define PB_LCD_MAIN BIT(7)
43 +
44 +#define PC_LED_EN BIT(0)
45 +#define PC_RST_TP_N BIT(1)
46 +#define PC_RST_LCD_N BIT(2)
47 +#define PC_RST_BRIDGE_N BIT(3)
48
49 struct attiny_lcd {
50 /* lock to serialise overall accesses to the Atmel */
51 @@ -37,99 +54,91 @@ static const struct regmap_config attiny
52 .reg_bits = 8,
53 .val_bits = 8,
54 .disable_locking = 1,
55 - .max_register = REG_PWM,
56 + .max_register = REG_WRITE_DATA_L,
57 .cache_type = REGCACHE_NONE,
58 };
59
60 static int attiny_lcd_power_enable(struct regulator_dev *rdev)
61 {
62 - struct mutex *lock = rdev_get_drvdata(rdev);
63 - unsigned int data;
64 - int ret, i;
65 + struct attiny_lcd *state = rdev_get_drvdata(rdev);
66
67 - mutex_lock(lock);
68 -
69 - regmap_write(rdev->regmap, REG_POWERON, 1);
70 - msleep(80);
71 + mutex_lock(&state->lock);
72
73 - /* Wait for nPWRDWN to go low to indicate poweron is done. */
74 - for (i = 0; i < 20; i++) {
75 - ret = regmap_read(rdev->regmap, REG_PORTB, &data);
76 - if (!ret) {
77 - if (data & BIT(0))
78 - break;
79 - }
80 - usleep_range(10000, 12000);
81 - }
82 - usleep_range(10000, 12000);
83 -
84 - if (ret)
85 - pr_err("%s: regmap_read_poll_timeout failed %d\n", __func__, ret);
86 + /* Ensure bridge, and tp stay in reset */
87 + regmap_write(rdev->regmap, REG_PORTC, 0);
88 + usleep_range(5000, 10000);
89
90 /* Default to the same orientation as the closed source
91 * firmware used for the panel. Runtime rotation
92 * configuration will be supported using VC4's plane
93 * orientation bits.
94 */
95 - regmap_write(rdev->regmap, REG_PORTA, BIT(2));
96 + regmap_write(rdev->regmap, REG_PORTA, PA_LCD_LR);
97 + usleep_range(5000, 10000);
98 + regmap_write(rdev->regmap, REG_PORTB, PB_LCD_MAIN);
99 + usleep_range(5000, 10000);
100 + /* Bring controllers out of reset */
101 + regmap_write(rdev->regmap, REG_PORTC,
102 + PC_LED_EN | PC_RST_BRIDGE_N | PC_RST_LCD_N | PC_RST_TP_N);
103 +
104 + msleep(80);
105 +
106 + regmap_write(rdev->regmap, REG_ADDR_H, 0x04);
107 + usleep_range(5000, 8000);
108 + regmap_write(rdev->regmap, REG_ADDR_L, 0x7c);
109 + usleep_range(5000, 8000);
110 + regmap_write(rdev->regmap, REG_WRITE_DATA_H, 0x00);
111 + usleep_range(5000, 8000);
112 + regmap_write(rdev->regmap, REG_WRITE_DATA_L, 0x00);
113
114 - mutex_unlock(lock);
115 + msleep(100);
116 +
117 + mutex_unlock(&state->lock);
118
119 return 0;
120 }
121
122 static int attiny_lcd_power_disable(struct regulator_dev *rdev)
123 {
124 - struct mutex *lock = rdev_get_drvdata(rdev);
125 + struct attiny_lcd *state = rdev_get_drvdata(rdev);
126
127 - mutex_lock(lock);
128 + mutex_lock(&state->lock);
129
130 regmap_write(rdev->regmap, REG_PWM, 0);
131 - regmap_write(rdev->regmap, REG_POWERON, 0);
132 + usleep_range(5000, 10000);
133 + regmap_write(rdev->regmap, REG_PORTA, 0);
134 + usleep_range(5000, 10000);
135 + regmap_write(rdev->regmap, REG_PORTB, PB_LCD_VCC_N);
136 + usleep_range(5000, 10000);
137 + regmap_write(rdev->regmap, REG_PORTC, 0);
138 msleep(30);
139
140 - mutex_unlock(lock);
141 + mutex_unlock(&state->lock);
142
143 return 0;
144 }
145
146 static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev)
147 {
148 - struct mutex *lock = rdev_get_drvdata(rdev);
149 + struct attiny_lcd *state = rdev_get_drvdata(rdev);
150 unsigned int data;
151 int ret, i;
152
153 - mutex_lock(lock);
154 -
155 - for (i = 0; i < 10; i++) {
156 - ret = regmap_read(rdev->regmap, REG_POWERON, &data);
157 - if (!ret)
158 - break;
159 - usleep_range(10000, 12000);
160 - }
161 - if (ret < 0) {
162 - mutex_unlock(lock);
163 - return ret;
164 - }
165 -
166 - if (!(data & BIT(0))) {
167 - mutex_unlock(lock);
168 - return 0;
169 - }
170 + mutex_lock(&state->lock);
171
172 for (i = 0; i < 10; i++) {
173 - ret = regmap_read(rdev->regmap, REG_PORTB, &data);
174 + ret = regmap_read(rdev->regmap, REG_PORTC, &data);
175 if (!ret)
176 break;
177 usleep_range(10000, 12000);
178 }
179
180 - mutex_unlock(lock);
181 + mutex_unlock(&state->lock);
182
183 if (ret < 0)
184 return ret;
185
186 - return data & BIT(0);
187 + return data & PC_RST_BRIDGE_N;
188 }
189
190 static const struct regulator_init_data attiny_regulator_default = {
191 @@ -256,7 +265,7 @@ static int attiny_i2c_probe(struct i2c_c
192 config.regmap = regmap;
193 config.of_node = i2c->dev.of_node;
194 config.init_data = &attiny_regulator_default;
195 - config.driver_data = &state->lock;
196 + config.driver_data = state;
197
198 rdev = devm_regulator_register(&i2c->dev, &attiny_regulator, &config);
199 if (IS_ERR(rdev)) {