1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "ili9881c_boe.h"
10 #include "gpio_if.h"
11 #include "hdf_bl.h"
12 #include "hdf_disp.h"
13 #include "osal.h"
14
Ili9881cBoeSendCmds(struct mipi_dsi_device * dsi,const struct DsiCmdDesc * cmds,int size)15 static int Ili9881cBoeSendCmds(struct mipi_dsi_device *dsi,
16 const struct DsiCmdDesc *cmds, int size)
17 {
18 int32_t i;
19
20 if (dsi == NULL) {
21 return -EINVAL;
22 }
23
24 for (i = 0; i < size; i++) {
25 mipi_dsi_generic_write(dsi, cmds[i].payload, cmds[i].dataLen);
26 if (cmds[i].delay) {
27 OsalMSleep(cmds[i].delay);
28 }
29 }
30 return HDF_SUCCESS;
31 }
32
ToIli9881cBoeDev(const struct PanelData * panel)33 static struct Ili9881cBoeDev *ToIli9881cBoeDev(const struct PanelData *panel)
34 {
35 return (struct Ili9881cBoeDev *)panel->object->priv;
36 }
37
SetGpioState(uint16_t gpio,uint16_t dir,uint16_t level,uint32_t delay)38 static SetGpioState(uint16_t gpio, uint16_t dir, uint16_t level, uint32_t delay)
39 {
40 int32_t ret;
41
42 ret = GpioSetDir(gpio, dir);
43 if (ret != HDF_SUCCESS) {
44 HDF_LOGE("%s GpioSetDir failed, ret:%d", __func__, ret);
45 return HDF_FAILURE;
46 }
47 ret = GpioWrite(gpio, level);
48 if (ret != HDF_SUCCESS) {
49 HDF_LOGE("%s GpioWrite failed, ret:%d", __func__, ret);
50 return HDF_FAILURE;
51 }
52 OsalMSleep(delay);
53 return HDF_SUCCESS;
54 }
55
Ili9881cBoePrepare(const struct Ili9881cBoeDev * ili9881cBoeDev)56 static int32_t Ili9881cBoePrepare(const struct Ili9881cBoeDev *ili9881cBoeDev)
57 {
58 int32_t i;
59 int32_t ret;
60 int32_t items;
61 struct GpioTiming *timing = NULL;
62
63 HDF_LOGI("%s()", __func__);
64 ret = regulator_enable(ili9881cBoeDev->supply);
65 if (ret < 0) {
66 HDF_LOGE("regulator_enable failed");
67 }
68 ret = SetGpioState(ili9881cBoeDev->avddGpio, GPIO_DIR_OUT, GPIO_VAL_HIGH, 5); /* delay 5ms */
69 if (ret != HDF_SUCCESS) {
70 HDF_LOGE("%s SetGpioState failed, gpio:%d", __func__, ili9881cBoeDev->avddGpio);
71 return HDF_FAILURE;
72 }
73 ret = SetGpioState(ili9881cBoeDev->aveeGpio, GPIO_DIR_OUT, GPIO_VAL_HIGH, 5);
74 if (ret != HDF_SUCCESS) {
75 HDF_LOGE("%s SetGpioState failed, gpio:%d", __func__, ili9881cBoeDev->aveeGpio);
76 return HDF_FAILURE;
77 }
78 ret = SetGpioState(ili9881cBoeDev->vghlGpio, GPIO_DIR_OUT, GPIO_VAL_HIGH, 5);
79 if (ret != HDF_SUCCESS) {
80 HDF_LOGE("%s SetGpioState failed, gpio:%d", __func__, ili9881cBoeDev->vghlGpio);
81 return HDF_FAILURE;
82 }
83 ret = SetGpioState(ili9881cBoeDev->tsrstGpio, GPIO_DIR_OUT, GPIO_VAL_HIGH, 5);
84 if (ret != HDF_SUCCESS) {
85 HDF_LOGE("%s SetGpioState failed, gpio:%d", __func__, ili9881cBoeDev->tsrstGpio);
86 return HDF_FAILURE;
87 }
88 ret = GpioSetDir(ili9881cBoeDev->resetGpio, GPIO_DIR_OUT);
89 if (ret != HDF_SUCCESS) {
90 HDF_LOGE("GpioSetDir failed, ret:%d", ret);
91 return HDF_FAILURE;
92 }
93 items = ili9881cBoeDev->rstOnSeq.items;
94 timing = ili9881cBoeDev->rstOnSeq.timing;
95 for (i = 0; i < items; i++) {
96 GpioWrite(ili9881cBoeDev->resetGpio, timing[i].level);
97 OsalMSleep(timing[i].delay);
98 }
99 return HDF_SUCCESS;
100 }
101
Ili9881cBoeUnprepare(const struct Ili9881cBoeDev * ili9881cBoeDev)102 static int32_t Ili9881cBoeUnprepare(const struct Ili9881cBoeDev *ili9881cBoeDev)
103 {
104 int32_t i;
105 int32_t ret;
106 int32_t items;
107 struct GpioTiming *timing = NULL;
108
109 HDF_LOGI("%s()", __func__);
110 ret = SetGpioState(ili9881cBoeDev->avddGpio, GPIO_DIR_OUT, GPIO_VAL_LOW, 5); /* delay 5ms */
111 if (ret != HDF_SUCCESS) {
112 HDF_LOGE("%s SetGpioState failed, gpio:%d", __func__, ili9881cBoeDev->avddGpio);
113 return HDF_FAILURE;
114 }
115 ret = SetGpioState(ili9881cBoeDev->aveeGpio, GPIO_DIR_OUT, GPIO_VAL_LOW, 5);
116 if (ret != HDF_SUCCESS) {
117 HDF_LOGE("%s SetGpioState failed, gpio:%d", __func__, ili9881cBoeDev->aveeGpio);
118 return HDF_FAILURE;
119 }
120 ret = SetGpioState(ili9881cBoeDev->vghlGpio, GPIO_DIR_OUT, GPIO_VAL_LOW, 5);
121 if (ret != HDF_SUCCESS) {
122 HDF_LOGE("%s SetGpioState failed, gpio:%d", __func__, ili9881cBoeDev->vghlGpio);
123 return HDF_FAILURE;
124 }
125 ret = SetGpioState(ili9881cBoeDev->tsrstGpio, GPIO_DIR_OUT, GPIO_VAL_LOW, 5);
126 if (ret != HDF_SUCCESS) {
127 HDF_LOGE("%s SetGpioState failed, gpio:%d", __func__, ili9881cBoeDev->tsrstGpio);
128 return HDF_FAILURE;
129 }
130 ret = GpioSetDir(ili9881cBoeDev->resetGpio, GPIO_DIR_OUT);
131 if (ret != HDF_SUCCESS) {
132 HDF_LOGE("GpioSetDir failed, ret:%d", ret);
133 return HDF_FAILURE;
134 }
135 items = ili9881cBoeDev->rstOffSeq.items;
136 timing = ili9881cBoeDev->rstOffSeq.timing;
137 for (i = 0; i < items; i++) {
138 GpioWrite(ili9881cBoeDev->resetGpio, timing[i].level);
139 OsalMSleep(timing[i].delay);
140 }
141 regulator_disable(ili9881cBoeDev->supply);
142 return HDF_SUCCESS;
143 }
144
Ili9881cBoeOn(struct PanelData * panel)145 static int32_t Ili9881cBoeOn(struct PanelData *panel)
146 {
147 int32_t ret;
148 struct Ili9881cBoeDev *ili9881cBoeDev = NULL;
149
150 HDF_LOGI("%s()", __func__);
151 ili9881cBoeDev = ToIli9881cBoeDev(panel);
152 ret = Ili9881cBoePrepare(ili9881cBoeDev);
153 if (ret != HDF_SUCCESS) {
154 HDF_LOGE("%s Ili9881cBoePrepare failed", __func__);
155 return HDF_FAILURE;
156 }
157 ret = Ili9881cBoeSendCmds(ili9881cBoeDev->dsiDev, g_panelOnCode,
158 sizeof(g_panelOnCode) / sizeof(g_panelOnCode[0]));
159 if (ret != HDF_SUCCESS) {
160 HDF_LOGE("%s Ili9881cBoeSendCmds failed", __func__);
161 return HDF_FAILURE;
162 }
163 return HDF_SUCCESS;
164 }
165
Ili9881cBoeOff(struct PanelData * panel)166 static int32_t Ili9881cBoeOff(struct PanelData *panel)
167 {
168 int32_t ret;
169 struct Ili9881cBoeDev *ili9881cBoeDev = NULL;
170
171 ili9881cBoeDev = ToIli9881cBoeDev(panel);
172 HDF_LOGI(" %s line = %d", __func__, __LINE__);
173 ret = Ili9881cBoeSendCmds(ili9881cBoeDev->dsiDev, g_panelOffCode,
174 sizeof(g_panelOffCode) / sizeof(g_panelOffCode[0]));
175 if (ret != HDF_SUCCESS) {
176 HDF_LOGE("%s Ili9881cBoeSendCmds failed", __func__);
177 return HDF_FAILURE;
178 }
179 ret = Ili9881cBoeUnprepare(ili9881cBoeDev);
180 if (ret != HDF_SUCCESS) {
181 HDF_LOGE("%s Ili9881cBoeUnprepare failed", __func__);
182 return HDF_FAILURE;
183 }
184 return HDF_SUCCESS;
185 }
186
Ili9881cBoeInit(struct PanelData * panel)187 static int32_t Ili9881cBoeInit(struct PanelData *panel)
188 {
189 return 0;
190 }
191
192 #define BLK_PWM_INDEX 2
193 #define PWM_MAX_PERIOD 40000
194 /* backlight setting */
195 #define MIN_LEVEL 0
196 #define MAX_LEVEL 255
197 #define DEFAULT_LEVEL 127
198
199 static struct PanelInfo g_panelInfo = {
200 .width = 800, /* width */
201 .height = 1280, /* height */
202 .hbp = 80, /* horizontal back porch */
203 .hfp = 80, /* horizontal front porch */
204 .hsw = 20, /* horizontal sync width */
205 .vbp = 12, /* vertical back porch */
206 .vfp = 20, /* vertical front porch */
207 .vsw = 4, /* vertical sync width */
208 .clockFreq = 76800000, /* clock */
209 .pWidth = 150, /* physical width */
210 .pHeight = 240, /* physical height */
211 .blk = { BLK_PWM, MIN_LEVEL, MAX_LEVEL, DEFAULT_LEVEL },
212 };
213
214 static struct GpioTiming g_rstOnSeq[] = {
215 {1, 5}, /* high, delay 5ms */
216 {0, 20}, /* low, delay 20ms */
217 {1, 30}, /* high, delay 30ms */
218 };
219
220 static struct GpioTiming g_rstOffSeq = {0, 10}; /* low, delay 10ms */
221
Ili9881cBoeResInit(struct Ili9881cBoeDev * ili9881cBoeDev)222 static void Ili9881cBoeResInit(struct Ili9881cBoeDev *ili9881cBoeDev)
223 {
224 ili9881cBoeDev->avddGpio = AVDD_GPIO;
225 ili9881cBoeDev->aveeGpio = AVEE_GPIO;
226 ili9881cBoeDev->vghlGpio = VGHL_GPIO;
227 ili9881cBoeDev->tsrstGpio = TSRST_GPIO;
228 ili9881cBoeDev->resetGpio = RESET_GPIO;
229 ili9881cBoeDev->rstOnSeq.items = sizeof(g_rstOnSeq) / sizeof(struct GpioTiming);
230 ili9881cBoeDev->rstOnSeq.timing = g_rstOnSeq;
231 ili9881cBoeDev->rstOffSeq.items = 1; /* number of reset off sequence */
232 ili9881cBoeDev->rstOffSeq.timing = &g_rstOffSeq;
233 ili9881cBoeDev->dsiDev->lanes = 4; /* number of active data lanes */
234 ili9881cBoeDev->dsiDev->format = 0; /* pixel format for video mode */
235 ili9881cBoeDev->dsiDev->mode_flags = 3; /* DSI operation mode related flags */
236 ili9881cBoeDev->panel.info = &g_panelInfo;
237 ili9881cBoeDev->panel.init = Ili9881cBoeInit;
238 ili9881cBoeDev->panel.on = Ili9881cBoeOn;
239 ili9881cBoeDev->panel.off = Ili9881cBoeOff;
240 ili9881cBoeDev->panel.priv = ili9881cBoeDev->dsiDev;
241 }
242
Ili9881cBoeEntryInit(struct HdfDeviceObject * object)243 int32_t Ili9881cBoeEntryInit(struct HdfDeviceObject *object)
244 {
245 struct device_node *panelNode = NULL;
246 struct Ili9881cBoeDev *ili9881cBoeDev = NULL;
247
248 ili9881cBoeDev = (struct Ili9881cBoeDev *)OsalMemCalloc(sizeof(struct Ili9881cBoeDev));
249 if (ili9881cBoeDev == NULL) {
250 HDF_LOGE("%s ili9881cBoeDev malloc fail", __func__);
251 return HDF_FAILURE;
252 }
253 panelNode = of_find_compatible_node(NULL, NULL, "sprd,generic-mipi-panel");
254 if (panelNode == NULL) {
255 HDF_LOGE("%s of_find_compatible_node fail", __func__);
256 goto FAIL;
257 }
258 ili9881cBoeDev->dsiDev = of_find_mipi_dsi_device_by_node(panelNode);
259 if (ili9881cBoeDev->dsiDev == NULL) {
260 HDF_LOGE("%s of_find_mipi_dsi_device_by_node fail", __func__);
261 goto FAIL;
262 }
263 ili9881cBoeDev->supply = devm_regulator_get(&ili9881cBoeDev->dsiDev->dev, "power");
264 if (ili9881cBoeDev->supply == NULL) {
265 HDF_LOGE("Get regulator fail");
266 goto FAIL;
267 }
268 Ili9881cBoeResInit(ili9881cBoeDev);
269 ili9881cBoeDev->panel.blDev = GetBacklightDev("hdf_pwm");
270 if (ili9881cBoeDev->panel.blDev == NULL) {
271 HDF_LOGE("%s GetBacklightDev fail", __func__);
272 goto FAIL;
273 }
274 ili9881cBoeDev->panel.object = object;
275 object->priv = ili9881cBoeDev;
276 if (RegisterPanel(&ili9881cBoeDev->panel) == HDF_SUCCESS) {
277 HDF_LOGI("%s success", __func__);
278 return HDF_SUCCESS;
279 }
280
281 FAIL:
282 OsalMemFree(ili9881cBoeDev);
283 return HDF_FAILURE;
284 }
285
286 struct HdfDriverEntry g_ili9881cBoeDevEntry = {
287 .moduleVersion = 1,
288 .moduleName = "LCD_ILI9881CBOE",
289 .Init = Ili9881cBoeEntryInit,
290 };
291
292 HDF_INIT(g_ili9881cBoeDevEntry);
293