]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/panel/panel-lg-lg4573.c
spi: Drop owner assignment from spi_drivers
[karo-tx-linux.git] / drivers / gpu / drm / panel / panel-lg-lg4573.c
1 /*
2  * Copyright (C) 2015 Heiko Schocher <hs@denx.de>
3  *
4  * from:
5  * drivers/gpu/drm/panel/panel-ld9040.c
6  * ld9040 AMOLED LCD drm_panel driver.
7  *
8  * Copyright (c) 2014 Samsung Electronics Co., Ltd
9  * Derived from drivers/video/backlight/ld9040.c
10  *
11  * Andrzej Hajda <a.hajda@samsung.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License version 2 as
15  * published by the Free Software Foundation.
16 */
17
18 #include <drm/drmP.h>
19 #include <drm/drm_panel.h>
20
21 #include <linux/gpio/consumer.h>
22 #include <linux/regulator/consumer.h>
23 #include <linux/spi/spi.h>
24
25 #include <video/mipi_display.h>
26 #include <video/of_videomode.h>
27 #include <video/videomode.h>
28
29 struct lg4573 {
30         struct drm_panel panel;
31         struct spi_device *spi;
32         struct videomode vm;
33 };
34
35 static inline struct lg4573 *panel_to_lg4573(struct drm_panel *panel)
36 {
37         return container_of(panel, struct lg4573, panel);
38 }
39
40 static int lg4573_spi_write_u16(struct lg4573 *ctx, u16 data)
41 {
42         struct spi_transfer xfer = {
43                 .len = 2,
44         };
45         u16 temp = cpu_to_be16(data);
46         struct spi_message msg;
47
48         dev_dbg(ctx->panel.dev, "writing data: %x\n", data);
49         xfer.tx_buf = &temp;
50         spi_message_init(&msg);
51         spi_message_add_tail(&xfer, &msg);
52
53         return spi_sync(ctx->spi, &msg);
54 }
55
56 static int lg4573_spi_write_u16_array(struct lg4573 *ctx, const u16 *buffer,
57                                       unsigned int count)
58 {
59         unsigned int i;
60         int ret;
61
62         for (i = 0; i < count; i++) {
63                 ret = lg4573_spi_write_u16(ctx, buffer[i]);
64                 if (ret)
65                         return ret;
66         }
67
68         return 0;
69 }
70
71 static int lg4573_spi_write_dcs(struct lg4573 *ctx, u8 dcs)
72 {
73         return lg4573_spi_write_u16(ctx, (0x70 << 8 | dcs));
74 }
75
76 static int lg4573_display_on(struct lg4573 *ctx)
77 {
78         int ret;
79
80         ret = lg4573_spi_write_dcs(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
81         if (ret)
82                 return ret;
83
84         msleep(5);
85
86         return lg4573_spi_write_dcs(ctx, MIPI_DCS_SET_DISPLAY_ON);
87 }
88
89 static int lg4573_display_off(struct lg4573 *ctx)
90 {
91         int ret;
92
93         ret = lg4573_spi_write_dcs(ctx, MIPI_DCS_SET_DISPLAY_OFF);
94         if (ret)
95                 return ret;
96
97         msleep(120);
98
99         return lg4573_spi_write_dcs(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
100 }
101
102 static int lg4573_display_mode_settings(struct lg4573 *ctx)
103 {
104         static const u16 display_mode_settings[] = {
105                 0x703A, 0x7270, 0x70B1, 0x7208,
106                 0x723B, 0x720F, 0x70B2, 0x7200,
107                 0x72C8, 0x70B3, 0x7200, 0x70B4,
108                 0x7200, 0x70B5, 0x7242, 0x7210,
109                 0x7210, 0x7200, 0x7220, 0x70B6,
110                 0x720B, 0x720F, 0x723C, 0x7213,
111                 0x7213, 0x72E8, 0x70B7, 0x7246,
112                 0x7206, 0x720C, 0x7200, 0x7200,
113         };
114
115         dev_dbg(ctx->panel.dev, "transfer display mode settings\n");
116         return lg4573_spi_write_u16_array(ctx, display_mode_settings,
117                                           ARRAY_SIZE(display_mode_settings));
118 }
119
120 static int lg4573_power_settings(struct lg4573 *ctx)
121 {
122         static const u16 power_settings[] = {
123                 0x70C0, 0x7201, 0x7211, 0x70C3,
124                 0x7207, 0x7203, 0x7204, 0x7204,
125                 0x7204, 0x70C4, 0x7212, 0x7224,
126                 0x7218, 0x7218, 0x7202, 0x7249,
127                 0x70C5, 0x726F, 0x70C6, 0x7241,
128                 0x7263,
129         };
130
131         dev_dbg(ctx->panel.dev, "transfer power settings\n");
132         return lg4573_spi_write_u16_array(ctx, power_settings,
133                                           ARRAY_SIZE(power_settings));
134 }
135
136 static int lg4573_gamma_settings(struct lg4573 *ctx)
137 {
138         static const u16 gamma_settings[] = {
139                 0x70D0, 0x7203, 0x7207, 0x7273,
140                 0x7235, 0x7200, 0x7201, 0x7220,
141                 0x7200, 0x7203, 0x70D1, 0x7203,
142                 0x7207, 0x7273, 0x7235, 0x7200,
143                 0x7201, 0x7220, 0x7200, 0x7203,
144                 0x70D2, 0x7203, 0x7207, 0x7273,
145                 0x7235, 0x7200, 0x7201, 0x7220,
146                 0x7200, 0x7203, 0x70D3, 0x7203,
147                 0x7207, 0x7273, 0x7235, 0x7200,
148                 0x7201, 0x7220, 0x7200, 0x7203,
149                 0x70D4, 0x7203, 0x7207, 0x7273,
150                 0x7235, 0x7200, 0x7201, 0x7220,
151                 0x7200, 0x7203, 0x70D5, 0x7203,
152                 0x7207, 0x7273, 0x7235, 0x7200,
153                 0x7201, 0x7220, 0x7200, 0x7203,
154         };
155
156         dev_dbg(ctx->panel.dev, "transfer gamma settings\n");
157         return lg4573_spi_write_u16_array(ctx, gamma_settings,
158                                           ARRAY_SIZE(gamma_settings));
159 }
160
161 static int lg4573_init(struct lg4573 *ctx)
162 {
163         int ret;
164
165         dev_dbg(ctx->panel.dev, "initializing LCD\n");
166
167         ret = lg4573_display_mode_settings(ctx);
168         if (ret)
169                 return ret;
170
171         ret = lg4573_power_settings(ctx);
172         if (ret)
173                 return ret;
174
175         return lg4573_gamma_settings(ctx);
176 }
177
178 static int lg4573_power_on(struct lg4573 *ctx)
179 {
180         return lg4573_display_on(ctx);
181 }
182
183 static int lg4573_disable(struct drm_panel *panel)
184 {
185         struct lg4573 *ctx = panel_to_lg4573(panel);
186
187         return lg4573_display_off(ctx);
188 }
189
190 static int lg4573_enable(struct drm_panel *panel)
191 {
192         struct lg4573 *ctx = panel_to_lg4573(panel);
193
194         lg4573_init(ctx);
195
196         return lg4573_power_on(ctx);
197 }
198
199 static const struct drm_display_mode default_mode = {
200         .clock = 27000,
201         .hdisplay = 480,
202         .hsync_start = 480 + 10,
203         .hsync_end = 480 + 10 + 59,
204         .htotal = 480 + 10 + 59 + 10,
205         .vdisplay = 800,
206         .vsync_start = 800 + 15,
207         .vsync_end = 800 + 15 + 15,
208         .vtotal = 800 + 15 + 15 + 15,
209         .vrefresh = 60,
210 };
211
212 static int lg4573_get_modes(struct drm_panel *panel)
213 {
214         struct drm_connector *connector = panel->connector;
215         struct drm_display_mode *mode;
216
217         mode = drm_mode_duplicate(panel->drm, &default_mode);
218         if (!mode) {
219                 dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
220                         default_mode.hdisplay, default_mode.vdisplay,
221                         default_mode.vrefresh);
222                 return -ENOMEM;
223         }
224
225         drm_mode_set_name(mode);
226
227         mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
228         drm_mode_probed_add(connector, mode);
229
230         panel->connector->display_info.width_mm = 61;
231         panel->connector->display_info.height_mm = 103;
232
233         return 1;
234 }
235
236 static const struct drm_panel_funcs lg4573_drm_funcs = {
237         .disable = lg4573_disable,
238         .enable = lg4573_enable,
239         .get_modes = lg4573_get_modes,
240 };
241
242 static int lg4573_probe(struct spi_device *spi)
243 {
244         struct lg4573 *ctx;
245         int ret;
246
247         ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL);
248         if (!ctx)
249                 return -ENOMEM;
250
251         ctx->spi = spi;
252
253         spi_set_drvdata(spi, ctx);
254         spi->bits_per_word = 8;
255
256         ret = spi_setup(spi);
257         if (ret < 0) {
258                 dev_err(&spi->dev, "SPI setup failed: %d\n", ret);
259                 return ret;
260         }
261
262         drm_panel_init(&ctx->panel);
263         ctx->panel.dev = &spi->dev;
264         ctx->panel.funcs = &lg4573_drm_funcs;
265
266         return drm_panel_add(&ctx->panel);
267 }
268
269 static int lg4573_remove(struct spi_device *spi)
270 {
271         struct lg4573 *ctx = spi_get_drvdata(spi);
272
273         lg4573_display_off(ctx);
274         drm_panel_remove(&ctx->panel);
275
276         return 0;
277 }
278
279 static const struct of_device_id lg4573_of_match[] = {
280         { .compatible = "lg,lg4573" },
281         { }
282 };
283 MODULE_DEVICE_TABLE(of, lg4573_of_match);
284
285 static struct spi_driver lg4573_driver = {
286         .probe = lg4573_probe,
287         .remove = lg4573_remove,
288         .driver = {
289                 .name = "lg4573",
290                 .of_match_table = lg4573_of_match,
291         },
292 };
293 module_spi_driver(lg4573_driver);
294
295 MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
296 MODULE_DESCRIPTION("lg4573 LCD Driver");
297 MODULE_LICENSE("GPL v2");