Merge tag 'drm-misc-next-2022-02-23' of git://anongit.freedesktop.org/drm/drm-misc...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / solomon / ssd130x.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * DRM driver for Solomon SSD130x OLED displays
4  *
5  * Copyright 2022 Red Hat Inc.
6  * Author: Javier Martinez Canillas <javierm@redhat.com>
7  *
8  * Based on drivers/video/fbdev/ssd1307fb.c
9  * Copyright 2012 Free Electrons
10  */
11
12 #include <linux/backlight.h>
13 #include <linux/bitfield.h>
14 #include <linux/bits.h>
15 #include <linux/delay.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/property.h>
18 #include <linux/pwm.h>
19 #include <linux/regulator/consumer.h>
20
21 #include <drm/drm_atomic_helper.h>
22 #include <drm/drm_damage_helper.h>
23 #include <drm/drm_fb_cma_helper.h>
24 #include <drm/drm_fb_helper.h>
25 #include <drm/drm_format_helper.h>
26 #include <drm/drm_gem_atomic_helper.h>
27 #include <drm/drm_gem_framebuffer_helper.h>
28 #include <drm/drm_gem_shmem_helper.h>
29 #include <drm/drm_managed.h>
30 #include <drm/drm_modes.h>
31 #include <drm/drm_rect.h>
32 #include <drm/drm_probe_helper.h>
33
34 #include "ssd130x.h"
35
36 #define DRIVER_NAME     "ssd130x"
37 #define DRIVER_DESC     "DRM driver for Solomon SSD130x OLED displays"
38 #define DRIVER_DATE     "20220131"
39 #define DRIVER_MAJOR    1
40 #define DRIVER_MINOR    0
41
42 #define SSD130X_DATA                            0x40
43 #define SSD130X_COMMAND                         0x80
44
45 #define SSD130X_SET_ADDRESS_MODE                0x20
46 #define SSD130X_SET_COL_RANGE                   0x21
47 #define SSD130X_SET_PAGE_RANGE                  0x22
48 #define SSD130X_CONTRAST                        0x81
49 #define SSD130X_SET_LOOKUP_TABLE                0x91
50 #define SSD130X_CHARGE_PUMP                     0x8d
51 #define SSD130X_SEG_REMAP_ON                    0xa1
52 #define SSD130X_DISPLAY_OFF                     0xae
53 #define SSD130X_SET_MULTIPLEX_RATIO             0xa8
54 #define SSD130X_DISPLAY_ON                      0xaf
55 #define SSD130X_START_PAGE_ADDRESS              0xb0
56 #define SSD130X_SET_COM_SCAN_DIR                0xc0
57 #define SSD130X_SET_DISPLAY_OFFSET              0xd3
58 #define SSD130X_SET_CLOCK_FREQ                  0xd5
59 #define SSD130X_SET_AREA_COLOR_MODE             0xd8
60 #define SSD130X_SET_PRECHARGE_PERIOD            0xd9
61 #define SSD130X_SET_COM_PINS_CONFIG             0xda
62 #define SSD130X_SET_VCOMH                       0xdb
63
64 #define SSD130X_SET_COM_SCAN_DIR_MASK           GENMASK(3, 2)
65 #define SSD130X_SET_COM_SCAN_DIR_SET(val)       FIELD_PREP(SSD130X_SET_COM_SCAN_DIR_MASK, (val))
66 #define SSD130X_SET_CLOCK_DIV_MASK              GENMASK(3, 0)
67 #define SSD130X_SET_CLOCK_DIV_SET(val)          FIELD_PREP(SSD130X_SET_CLOCK_DIV_MASK, (val))
68 #define SSD130X_SET_CLOCK_FREQ_MASK             GENMASK(7, 4)
69 #define SSD130X_SET_CLOCK_FREQ_SET(val)         FIELD_PREP(SSD130X_SET_CLOCK_FREQ_MASK, (val))
70 #define SSD130X_SET_PRECHARGE_PERIOD1_MASK      GENMASK(3, 0)
71 #define SSD130X_SET_PRECHARGE_PERIOD1_SET(val)  FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD1_MASK, (val))
72 #define SSD130X_SET_PRECHARGE_PERIOD2_MASK      GENMASK(7, 4)
73 #define SSD130X_SET_PRECHARGE_PERIOD2_SET(val)  FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD2_MASK, (val))
74 #define SSD130X_SET_COM_PINS_CONFIG1_MASK       GENMASK(4, 4)
75 #define SSD130X_SET_COM_PINS_CONFIG1_SET(val)   FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG1_MASK, !(val))
76 #define SSD130X_SET_COM_PINS_CONFIG2_MASK       GENMASK(5, 5)
77 #define SSD130X_SET_COM_PINS_CONFIG2_SET(val)   FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG2_MASK, (val))
78
79 #define SSD130X_SET_ADDRESS_MODE_HORIZONTAL     0x00
80 #define SSD130X_SET_ADDRESS_MODE_VERTICAL       0x01
81 #define SSD130X_SET_ADDRESS_MODE_PAGE           0x02
82
83 #define SSD130X_SET_AREA_COLOR_MODE_ENABLE      0x1e
84 #define SSD130X_SET_AREA_COLOR_MODE_LOW_POWER   0x05
85
86 #define MAX_CONTRAST 255
87
88 static inline struct ssd130x_device *drm_to_ssd130x(struct drm_device *drm)
89 {
90         return container_of(drm, struct ssd130x_device, drm);
91 }
92
93 /*
94  * Helper to write data (SSD130X_DATA) to the device.
95  */
96 static int ssd130x_write_data(struct ssd130x_device *ssd130x, u8 *values, int count)
97 {
98         return regmap_bulk_write(ssd130x->regmap, SSD130X_DATA, values, count);
99 }
100
101 /*
102  * Helper to write command (SSD130X_COMMAND). The fist variadic argument
103  * is the command to write and the following are the command options.
104  *
105  * Note that the ssd130x protocol requires each command and option to be
106  * written as a SSD130X_COMMAND device register value. That is why a call
107  * to regmap_write(..., SSD130X_COMMAND, ...) is done for each argument.
108  */
109 static int ssd130x_write_cmd(struct ssd130x_device *ssd130x, int count,
110                              /* u8 cmd, u8 option, ... */...)
111 {
112         va_list ap;
113         u8 value;
114         int ret;
115
116         va_start(ap, count);
117
118         do {
119                 value = va_arg(ap, int);
120                 ret = regmap_write(ssd130x->regmap, SSD130X_COMMAND, value);
121                 if (ret)
122                         goto out_end;
123         } while (--count);
124
125 out_end:
126         va_end(ap);
127
128         return ret;
129 }
130
131 static int ssd130x_set_col_range(struct ssd130x_device *ssd130x,
132                                  u8 col_start, u8 cols)
133 {
134         u8 col_end = col_start + cols - 1;
135         int ret;
136
137         if (col_start == ssd130x->col_start && col_end == ssd130x->col_end)
138                 return 0;
139
140         ret = ssd130x_write_cmd(ssd130x, 3, SSD130X_SET_COL_RANGE, col_start, col_end);
141         if (ret < 0)
142                 return ret;
143
144         ssd130x->col_start = col_start;
145         ssd130x->col_end = col_end;
146         return 0;
147 }
148
149 static int ssd130x_set_page_range(struct ssd130x_device *ssd130x,
150                                   u8 page_start, u8 pages)
151 {
152         u8 page_end = page_start + pages - 1;
153         int ret;
154
155         if (page_start == ssd130x->page_start && page_end == ssd130x->page_end)
156                 return 0;
157
158         ret = ssd130x_write_cmd(ssd130x, 3, SSD130X_SET_PAGE_RANGE, page_start, page_end);
159         if (ret < 0)
160                 return ret;
161
162         ssd130x->page_start = page_start;
163         ssd130x->page_end = page_end;
164         return 0;
165 }
166
167 static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x)
168 {
169         struct device *dev = ssd130x->dev;
170         struct pwm_state pwmstate;
171
172         ssd130x->pwm = pwm_get(dev, NULL);
173         if (IS_ERR(ssd130x->pwm)) {
174                 dev_err(dev, "Could not get PWM from firmware description!\n");
175                 return PTR_ERR(ssd130x->pwm);
176         }
177
178         pwm_init_state(ssd130x->pwm, &pwmstate);
179         pwm_set_relative_duty_cycle(&pwmstate, 50, 100);
180         pwm_apply_state(ssd130x->pwm, &pwmstate);
181
182         /* Enable the PWM */
183         pwm_enable(ssd130x->pwm);
184
185         dev_dbg(dev, "Using PWM%d with a %lluns period.\n",
186                 ssd130x->pwm->pwm, pwm_get_period(ssd130x->pwm));
187
188         return 0;
189 }
190
191 static void ssd130x_reset(struct ssd130x_device *ssd130x)
192 {
193         if (!ssd130x->reset)
194                 return;
195
196         /* Reset the screen */
197         gpiod_set_value_cansleep(ssd130x->reset, 1);
198         udelay(4);
199         gpiod_set_value_cansleep(ssd130x->reset, 0);
200         udelay(4);
201 }
202
203 static int ssd130x_power_on(struct ssd130x_device *ssd130x)
204 {
205         struct device *dev = ssd130x->dev;
206         int ret;
207
208         ssd130x_reset(ssd130x);
209
210         ret = regulator_enable(ssd130x->vcc_reg);
211         if (ret) {
212                 dev_err(dev, "Failed to enable VCC: %d\n", ret);
213                 return ret;
214         }
215
216         if (ssd130x->device_info->need_pwm) {
217                 ret = ssd130x_pwm_enable(ssd130x);
218                 if (ret) {
219                         dev_err(dev, "Failed to enable PWM: %d\n", ret);
220                         regulator_disable(ssd130x->vcc_reg);
221                         return ret;
222                 }
223         }
224
225         return 0;
226 }
227
228 static void ssd130x_power_off(struct ssd130x_device *ssd130x)
229 {
230         pwm_disable(ssd130x->pwm);
231         pwm_put(ssd130x->pwm);
232
233         regulator_disable(ssd130x->vcc_reg);
234 }
235
236 static int ssd130x_init(struct ssd130x_device *ssd130x)
237 {
238         u32 precharge, dclk, com_invdir, compins, chargepump;
239         int ret;
240
241         /* Set initial contrast */
242         ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_CONTRAST, ssd130x->contrast);
243         if (ret < 0)
244                 return ret;
245
246         /* Set segment re-map */
247         if (ssd130x->seg_remap) {
248                 ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_SEG_REMAP_ON);
249                 if (ret < 0)
250                         return ret;
251         }
252
253         /* Set COM direction */
254         com_invdir = (SSD130X_SET_COM_SCAN_DIR |
255                       SSD130X_SET_COM_SCAN_DIR_SET(ssd130x->com_invdir));
256         ret = ssd130x_write_cmd(ssd130x,  1, com_invdir);
257         if (ret < 0)
258                 return ret;
259
260         /* Set multiplex ratio value */
261         ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_MULTIPLEX_RATIO, ssd130x->height - 1);
262         if (ret < 0)
263                 return ret;
264
265         /* set display offset value */
266         ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_DISPLAY_OFFSET, ssd130x->com_offset);
267         if (ret < 0)
268                 return ret;
269
270         /* Set clock frequency */
271         dclk = (SSD130X_SET_CLOCK_DIV_SET(ssd130x->dclk_div - 1) |
272                 SSD130X_SET_CLOCK_FREQ_SET(ssd130x->dclk_frq));
273         ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_CLOCK_FREQ, dclk);
274         if (ret < 0)
275                 return ret;
276
277         /* Set Area Color Mode ON/OFF & Low Power Display Mode */
278         if (ssd130x->area_color_enable || ssd130x->low_power) {
279                 u32 mode = 0;
280
281                 if (ssd130x->area_color_enable)
282                         mode |= SSD130X_SET_AREA_COLOR_MODE_ENABLE;
283
284                 if (ssd130x->low_power)
285                         mode |= SSD130X_SET_AREA_COLOR_MODE_LOW_POWER;
286
287                 ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_AREA_COLOR_MODE, mode);
288                 if (ret < 0)
289                         return ret;
290         }
291
292         /* Set precharge period in number of ticks from the internal clock */
293         precharge = (SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep1) |
294                      SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep2));
295         ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_PRECHARGE_PERIOD, precharge);
296         if (ret < 0)
297                 return ret;
298
299         /* Set COM pins configuration */
300         compins = BIT(1);
301         compins |= (SSD130X_SET_COM_PINS_CONFIG1_SET(ssd130x->com_seq) |
302                     SSD130X_SET_COM_PINS_CONFIG2_SET(ssd130x->com_lrremap));
303         ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_COM_PINS_CONFIG, compins);
304         if (ret < 0)
305                 return ret;
306
307         /* Set VCOMH */
308         ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_VCOMH, ssd130x->vcomh);
309         if (ret < 0)
310                 return ret;
311
312         /* Turn on the DC-DC Charge Pump */
313         chargepump = BIT(4);
314
315         if (ssd130x->device_info->need_chargepump)
316                 chargepump |= BIT(2);
317
318         ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_CHARGE_PUMP, chargepump);
319         if (ret < 0)
320                 return ret;
321
322         /* Set lookup table */
323         if (ssd130x->lookup_table_set) {
324                 int i;
325
326                 ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_SET_LOOKUP_TABLE);
327                 if (ret < 0)
328                         return ret;
329
330                 for (i = 0; i < ARRAY_SIZE(ssd130x->lookup_table); i++) {
331                         u8 val = ssd130x->lookup_table[i];
332
333                         if (val < 31 || val > 63)
334                                 dev_warn(ssd130x->dev,
335                                          "lookup table index %d value out of range 31 <= %d <= 63\n",
336                                          i, val);
337                         ret = ssd130x_write_cmd(ssd130x, 1, val);
338                         if (ret < 0)
339                                 return ret;
340                 }
341         }
342
343         /* Switch to horizontal addressing mode */
344         return ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_ADDRESS_MODE,
345                                  SSD130X_SET_ADDRESS_MODE_HORIZONTAL);
346 }
347
348 static int ssd130x_update_rect(struct ssd130x_device *ssd130x, u8 *buf,
349                                struct drm_rect *rect)
350 {
351         unsigned int x = rect->x1;
352         unsigned int y = rect->y1;
353         unsigned int width = drm_rect_width(rect);
354         unsigned int height = drm_rect_height(rect);
355         unsigned int line_length = DIV_ROUND_UP(width, 8);
356         unsigned int pages = DIV_ROUND_UP(y % 8 + height, 8);
357         u32 array_idx = 0;
358         int ret, i, j, k;
359         u8 *data_array = NULL;
360
361         data_array = kcalloc(width, pages, GFP_KERNEL);
362         if (!data_array)
363                 return -ENOMEM;
364
365         /*
366          * The screen is divided in pages, each having a height of 8
367          * pixels, and the width of the screen. When sending a byte of
368          * data to the controller, it gives the 8 bits for the current
369          * column. I.e, the first byte are the 8 bits of the first
370          * column, then the 8 bits for the second column, etc.
371          *
372          *
373          * Representation of the screen, assuming it is 5 bits
374          * wide. Each letter-number combination is a bit that controls
375          * one pixel.
376          *
377          * A0 A1 A2 A3 A4
378          * B0 B1 B2 B3 B4
379          * C0 C1 C2 C3 C4
380          * D0 D1 D2 D3 D4
381          * E0 E1 E2 E3 E4
382          * F0 F1 F2 F3 F4
383          * G0 G1 G2 G3 G4
384          * H0 H1 H2 H3 H4
385          *
386          * If you want to update this screen, you need to send 5 bytes:
387          *  (1) A0 B0 C0 D0 E0 F0 G0 H0
388          *  (2) A1 B1 C1 D1 E1 F1 G1 H1
389          *  (3) A2 B2 C2 D2 E2 F2 G2 H2
390          *  (4) A3 B3 C3 D3 E3 F3 G3 H3
391          *  (5) A4 B4 C4 D4 E4 F4 G4 H4
392          */
393
394         ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset + x, width);
395         if (ret < 0)
396                 goto out_free;
397
398         ret = ssd130x_set_page_range(ssd130x, ssd130x->page_offset + y / 8, pages);
399         if (ret < 0)
400                 goto out_free;
401
402         for (i = y / 8; i < y / 8 + pages; i++) {
403                 int m = 8;
404
405                 /* Last page may be partial */
406                 if (8 * (i + 1) > ssd130x->height)
407                         m = ssd130x->height % 8;
408                 for (j = x; j < x + width; j++) {
409                         u8 data = 0;
410
411                         for (k = 0; k < m; k++) {
412                                 u8 byte = buf[(8 * i + k) * line_length + j / 8];
413                                 u8 bit = (byte >> (j % 8)) & 1;
414
415                                 data |= bit << k;
416                         }
417                         data_array[array_idx++] = data;
418                 }
419         }
420
421         ret = ssd130x_write_data(ssd130x, data_array, width * pages);
422
423 out_free:
424         kfree(data_array);
425         return ret;
426 }
427
428 static void ssd130x_clear_screen(struct ssd130x_device *ssd130x)
429 {
430         u8 *buf = NULL;
431         struct drm_rect fullscreen = {
432                 .x1 = 0,
433                 .x2 = ssd130x->width,
434                 .y1 = 0,
435                 .y2 = ssd130x->height,
436         };
437
438         buf = kcalloc(ssd130x->width, ssd130x->height, GFP_KERNEL);
439         if (!buf)
440                 return;
441
442         ssd130x_update_rect(ssd130x, buf, &fullscreen);
443
444         kfree(buf);
445 }
446
447 static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_map *map,
448                                 struct drm_rect *rect)
449 {
450         struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);
451         void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
452         int ret = 0;
453         u8 *buf = NULL;
454
455         buf = kcalloc(fb->width, fb->height, GFP_KERNEL);
456         if (!buf)
457                 return -ENOMEM;
458
459         drm_fb_xrgb8888_to_mono_reversed(buf, 0, vmap, fb, rect);
460
461         ssd130x_update_rect(ssd130x, buf, rect);
462
463         kfree(buf);
464
465         return ret;
466 }
467
468 static int ssd130x_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
469                                            const struct drm_display_mode *mode)
470 {
471         struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
472
473         if (mode->hdisplay != ssd130x->mode.hdisplay &&
474             mode->vdisplay != ssd130x->mode.vdisplay)
475                 return MODE_ONE_SIZE;
476
477         if (mode->hdisplay != ssd130x->mode.hdisplay)
478                 return MODE_ONE_WIDTH;
479
480         if (mode->vdisplay != ssd130x->mode.vdisplay)
481                 return MODE_ONE_HEIGHT;
482
483         return MODE_OK;
484 }
485
486 static void ssd130x_display_pipe_enable(struct drm_simple_display_pipe *pipe,
487                                         struct drm_crtc_state *crtc_state,
488                                         struct drm_plane_state *plane_state)
489 {
490         struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
491         struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
492         struct drm_device *drm = &ssd130x->drm;
493         int idx, ret;
494
495         ret = ssd130x_power_on(ssd130x);
496         if (ret)
497                 return;
498
499         ret = ssd130x_init(ssd130x);
500         if (ret)
501                 goto out_power_off;
502
503         if (!drm_dev_enter(drm, &idx))
504                 goto out_power_off;
505
506         ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &plane_state->dst);
507
508         ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_ON);
509
510         backlight_enable(ssd130x->bl_dev);
511
512         drm_dev_exit(idx);
513
514         return;
515 out_power_off:
516         ssd130x_power_off(ssd130x);
517 }
518
519 static void ssd130x_display_pipe_disable(struct drm_simple_display_pipe *pipe)
520 {
521         struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
522         struct drm_device *drm = &ssd130x->drm;
523         int idx;
524
525         if (!drm_dev_enter(drm, &idx))
526                 return;
527
528         ssd130x_clear_screen(ssd130x);
529
530         backlight_disable(ssd130x->bl_dev);
531
532         ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_OFF);
533
534         ssd130x_power_off(ssd130x);
535
536         drm_dev_exit(idx);
537 }
538
539 static void ssd130x_display_pipe_update(struct drm_simple_display_pipe *pipe,
540                                         struct drm_plane_state *old_plane_state)
541 {
542         struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
543         struct drm_plane_state *plane_state = pipe->plane.state;
544         struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
545         struct drm_framebuffer *fb = plane_state->fb;
546         struct drm_device *drm = &ssd130x->drm;
547         struct drm_rect src_clip, dst_clip;
548         int idx;
549
550         if (!fb)
551                 return;
552
553         if (!pipe->crtc.state->active)
554                 return;
555
556         if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip))
557                 return;
558
559         dst_clip = plane_state->dst;
560         if (!drm_rect_intersect(&dst_clip, &src_clip))
561                 return;
562
563         if (!drm_dev_enter(drm, &idx))
564                 return;
565
566         ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip);
567
568         drm_dev_exit(idx);
569 }
570
571 static const struct drm_simple_display_pipe_funcs ssd130x_pipe_funcs = {
572         .mode_valid = ssd130x_display_pipe_mode_valid,
573         .enable = ssd130x_display_pipe_enable,
574         .disable = ssd130x_display_pipe_disable,
575         .update = ssd130x_display_pipe_update,
576         DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
577 };
578
579 static int ssd130x_connector_get_modes(struct drm_connector *connector)
580 {
581         struct ssd130x_device *ssd130x = drm_to_ssd130x(connector->dev);
582         struct drm_display_mode *mode = &ssd130x->mode;
583         struct device *dev = ssd130x->dev;
584
585         mode = drm_mode_duplicate(connector->dev, &ssd130x->mode);
586         if (!mode) {
587                 dev_err(dev, "Failed to duplicated mode\n");
588                 return 0;
589         }
590
591         drm_mode_probed_add(connector, mode);
592         drm_set_preferred_mode(connector, mode->hdisplay, mode->vdisplay);
593
594         /* There is only a single mode */
595         return 1;
596 }
597
598 static const struct drm_connector_helper_funcs ssd130x_connector_helper_funcs = {
599         .get_modes = ssd130x_connector_get_modes,
600 };
601
602 static const struct drm_connector_funcs ssd130x_connector_funcs = {
603         .reset = drm_atomic_helper_connector_reset,
604         .fill_modes = drm_helper_probe_single_connector_modes,
605         .destroy = drm_connector_cleanup,
606         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
607         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
608 };
609
610 static const struct drm_mode_config_funcs ssd130x_mode_config_funcs = {
611         .fb_create = drm_gem_fb_create_with_dirty,
612         .atomic_check = drm_atomic_helper_check,
613         .atomic_commit = drm_atomic_helper_commit,
614 };
615
616 static const uint32_t ssd130x_formats[] = {
617         DRM_FORMAT_XRGB8888,
618 };
619
620 DEFINE_DRM_GEM_FOPS(ssd130x_fops);
621
622 static const struct drm_driver ssd130x_drm_driver = {
623         DRM_GEM_SHMEM_DRIVER_OPS,
624         .name                   = DRIVER_NAME,
625         .desc                   = DRIVER_DESC,
626         .date                   = DRIVER_DATE,
627         .major                  = DRIVER_MAJOR,
628         .minor                  = DRIVER_MINOR,
629         .driver_features        = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
630         .fops                   = &ssd130x_fops,
631 };
632
633 static int ssd130x_update_bl(struct backlight_device *bdev)
634 {
635         struct ssd130x_device *ssd130x = bl_get_data(bdev);
636         int brightness = backlight_get_brightness(bdev);
637         int ret;
638
639         ssd130x->contrast = brightness;
640
641         ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_CONTRAST);
642         if (ret < 0)
643                 return ret;
644
645         ret = ssd130x_write_cmd(ssd130x, 1, ssd130x->contrast);
646         if (ret < 0)
647                 return ret;
648
649         return 0;
650 }
651
652 static const struct backlight_ops ssd130xfb_bl_ops = {
653         .update_status  = ssd130x_update_bl,
654 };
655
656 static void ssd130x_parse_properties(struct ssd130x_device *ssd130x)
657 {
658         struct device *dev = ssd130x->dev;
659
660         if (device_property_read_u32(dev, "solomon,width", &ssd130x->width))
661                 ssd130x->width = 96;
662
663         if (device_property_read_u32(dev, "solomon,height", &ssd130x->height))
664                 ssd130x->height = 16;
665
666         if (device_property_read_u32(dev, "solomon,page-offset", &ssd130x->page_offset))
667                 ssd130x->page_offset = 1;
668
669         if (device_property_read_u32(dev, "solomon,col-offset", &ssd130x->col_offset))
670                 ssd130x->col_offset = 0;
671
672         if (device_property_read_u32(dev, "solomon,com-offset", &ssd130x->com_offset))
673                 ssd130x->com_offset = 0;
674
675         if (device_property_read_u32(dev, "solomon,prechargep1", &ssd130x->prechargep1))
676                 ssd130x->prechargep1 = 2;
677
678         if (device_property_read_u32(dev, "solomon,prechargep2", &ssd130x->prechargep2))
679                 ssd130x->prechargep2 = 2;
680
681         if (!device_property_read_u8_array(dev, "solomon,lookup-table",
682                                            ssd130x->lookup_table,
683                                            ARRAY_SIZE(ssd130x->lookup_table)))
684                 ssd130x->lookup_table_set = 1;
685
686         ssd130x->seg_remap = !device_property_read_bool(dev, "solomon,segment-no-remap");
687         ssd130x->com_seq = device_property_read_bool(dev, "solomon,com-seq");
688         ssd130x->com_lrremap = device_property_read_bool(dev, "solomon,com-lrremap");
689         ssd130x->com_invdir = device_property_read_bool(dev, "solomon,com-invdir");
690         ssd130x->area_color_enable =
691                 device_property_read_bool(dev, "solomon,area-color-enable");
692         ssd130x->low_power = device_property_read_bool(dev, "solomon,low-power");
693
694         ssd130x->contrast = 127;
695         ssd130x->vcomh = ssd130x->device_info->default_vcomh;
696
697         /* Setup display timing */
698         if (device_property_read_u32(dev, "solomon,dclk-div", &ssd130x->dclk_div))
699                 ssd130x->dclk_div = ssd130x->device_info->default_dclk_div;
700         if (device_property_read_u32(dev, "solomon,dclk-frq", &ssd130x->dclk_frq))
701                 ssd130x->dclk_frq = ssd130x->device_info->default_dclk_frq;
702 }
703
704 static int ssd130x_init_modeset(struct ssd130x_device *ssd130x)
705 {
706         struct drm_display_mode *mode = &ssd130x->mode;
707         struct device *dev = ssd130x->dev;
708         struct drm_device *drm = &ssd130x->drm;
709         unsigned long max_width, max_height;
710         int ret;
711
712         ret = drmm_mode_config_init(drm);
713         if (ret) {
714                 dev_err(dev, "DRM mode config init failed: %d\n", ret);
715                 return ret;
716         }
717
718         mode->type = DRM_MODE_TYPE_DRIVER;
719         mode->clock = 1;
720         mode->hdisplay = mode->htotal = ssd130x->width;
721         mode->hsync_start = mode->hsync_end = ssd130x->width;
722         mode->vdisplay = mode->vtotal = ssd130x->height;
723         mode->vsync_start = mode->vsync_end = ssd130x->height;
724         mode->width_mm = 27;
725         mode->height_mm = 27;
726
727         max_width = max_t(unsigned long, mode->hdisplay, DRM_SHADOW_PLANE_MAX_WIDTH);
728         max_height = max_t(unsigned long, mode->vdisplay, DRM_SHADOW_PLANE_MAX_HEIGHT);
729
730         drm->mode_config.min_width = mode->hdisplay;
731         drm->mode_config.max_width = max_width;
732         drm->mode_config.min_height = mode->vdisplay;
733         drm->mode_config.max_height = max_height;
734         drm->mode_config.preferred_depth = 32;
735         drm->mode_config.funcs = &ssd130x_mode_config_funcs;
736
737         ret = drm_connector_init(drm, &ssd130x->connector, &ssd130x_connector_funcs,
738                                  DRM_MODE_CONNECTOR_Unknown);
739         if (ret) {
740                 dev_err(dev, "DRM connector init failed: %d\n", ret);
741                 return ret;
742         }
743
744         drm_connector_helper_add(&ssd130x->connector, &ssd130x_connector_helper_funcs);
745
746         ret = drm_simple_display_pipe_init(drm, &ssd130x->pipe, &ssd130x_pipe_funcs,
747                                            ssd130x_formats, ARRAY_SIZE(ssd130x_formats),
748                                            NULL, &ssd130x->connector);
749         if (ret) {
750                 dev_err(dev, "DRM simple display pipeline init failed: %d\n", ret);
751                 return ret;
752         }
753
754         drm_plane_enable_fb_damage_clips(&ssd130x->pipe.plane);
755
756         drm_mode_config_reset(drm);
757
758         return 0;
759 }
760
761 static int ssd130x_get_resources(struct ssd130x_device *ssd130x)
762 {
763         struct device *dev = ssd130x->dev;
764
765         ssd130x->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
766         if (IS_ERR(ssd130x->reset))
767                 return dev_err_probe(dev, PTR_ERR(ssd130x->reset),
768                                      "Failed to get reset gpio\n");
769
770         ssd130x->vcc_reg = devm_regulator_get(dev, "vcc");
771         if (IS_ERR(ssd130x->vcc_reg))
772                 return dev_err_probe(dev, PTR_ERR(ssd130x->vcc_reg),
773                                      "Failed to get VCC regulator\n");
774
775         return 0;
776 }
777
778 struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap)
779 {
780         struct ssd130x_device *ssd130x;
781         struct backlight_device *bl;
782         struct drm_device *drm;
783         int ret;
784
785         ssd130x = devm_drm_dev_alloc(dev, &ssd130x_drm_driver,
786                                      struct ssd130x_device, drm);
787         if (IS_ERR(ssd130x))
788                 return ERR_PTR(dev_err_probe(dev, PTR_ERR(ssd130x),
789                                              "Failed to allocate DRM device\n"));
790
791         drm = &ssd130x->drm;
792
793         ssd130x->dev = dev;
794         ssd130x->regmap = regmap;
795         ssd130x->device_info = device_get_match_data(dev);
796
797         ssd130x_parse_properties(ssd130x);
798
799         ret = ssd130x_get_resources(ssd130x);
800         if (ret)
801                 return ERR_PTR(ret);
802
803         bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
804                                             &ssd130xfb_bl_ops, NULL);
805         if (IS_ERR(bl))
806                 return ERR_PTR(dev_err_probe(dev, PTR_ERR(bl),
807                                              "Unable to register backlight device\n"));
808
809         bl->props.brightness = ssd130x->contrast;
810         bl->props.max_brightness = MAX_CONTRAST;
811         ssd130x->bl_dev = bl;
812
813         ret = ssd130x_init_modeset(ssd130x);
814         if (ret)
815                 return ERR_PTR(ret);
816
817         ret = drm_dev_register(drm, 0);
818         if (ret)
819                 return ERR_PTR(dev_err_probe(dev, ret, "DRM device register failed\n"));
820
821         drm_fbdev_generic_setup(drm, 0);
822
823         return ssd130x;
824 }
825 EXPORT_SYMBOL_GPL(ssd130x_probe);
826
827 int ssd130x_remove(struct ssd130x_device *ssd130x)
828 {
829         drm_dev_unplug(&ssd130x->drm);
830
831         return 0;
832 }
833 EXPORT_SYMBOL_GPL(ssd130x_remove);
834
835 void ssd130x_shutdown(struct ssd130x_device *ssd130x)
836 {
837         drm_atomic_helper_shutdown(&ssd130x->drm);
838 }
839 EXPORT_SYMBOL_GPL(ssd130x_shutdown);
840
841 MODULE_DESCRIPTION(DRIVER_DESC);
842 MODULE_AUTHOR("Javier Martinez Canillas <javierm@redhat.com>");
843 MODULE_LICENSE("GPL v2");