1 // SPDX-License-Identifier: GPL-2.0-only
3 * DRM driver for Solomon SSD130x OLED displays
5 * Copyright 2022 Red Hat Inc.
8 * Based on drivers/video/fbdev/ssd1307fb.c
9 * Copyright 2012 Free Electrons
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>
21 #include <drm/drm_atomic.h>
22 #include <drm/drm_atomic_helper.h>
23 #include <drm/drm_crtc_helper.h>
24 #include <drm/drm_damage_helper.h>
25 #include <drm/drm_edid.h>
26 #include <drm/drm_fbdev_generic.h>
27 #include <drm/drm_format_helper.h>
28 #include <drm/drm_framebuffer.h>
29 #include <drm/drm_gem_atomic_helper.h>
30 #include <drm/drm_gem_framebuffer_helper.h>
31 #include <drm/drm_gem_shmem_helper.h>
32 #include <drm/drm_managed.h>
33 #include <drm/drm_modes.h>
34 #include <drm/drm_rect.h>
35 #include <drm/drm_probe_helper.h>
39 #define DRIVER_NAME "ssd130x"
40 #define DRIVER_DESC "DRM driver for Solomon SSD130x OLED displays"
41 #define DRIVER_DATE "20220131"
42 #define DRIVER_MAJOR 1
43 #define DRIVER_MINOR 0
45 #define SSD130X_PAGE_COL_START_LOW 0x00
46 #define SSD130X_PAGE_COL_START_HIGH 0x10
47 #define SSD130X_SET_ADDRESS_MODE 0x20
48 #define SSD130X_SET_COL_RANGE 0x21
49 #define SSD130X_SET_PAGE_RANGE 0x22
50 #define SSD130X_CONTRAST 0x81
51 #define SSD130X_SET_LOOKUP_TABLE 0x91
52 #define SSD130X_CHARGE_PUMP 0x8d
53 #define SSD130X_SET_SEG_REMAP 0xa0
54 #define SSD130X_DISPLAY_OFF 0xae
55 #define SSD130X_SET_MULTIPLEX_RATIO 0xa8
56 #define SSD130X_DISPLAY_ON 0xaf
57 #define SSD130X_START_PAGE_ADDRESS 0xb0
58 #define SSD130X_SET_COM_SCAN_DIR 0xc0
59 #define SSD130X_SET_DISPLAY_OFFSET 0xd3
60 #define SSD130X_SET_CLOCK_FREQ 0xd5
61 #define SSD130X_SET_AREA_COLOR_MODE 0xd8
62 #define SSD130X_SET_PRECHARGE_PERIOD 0xd9
63 #define SSD130X_SET_COM_PINS_CONFIG 0xda
64 #define SSD130X_SET_VCOMH 0xdb
66 #define SSD130X_PAGE_COL_START_MASK GENMASK(3, 0)
67 #define SSD130X_PAGE_COL_START_HIGH_SET(val) FIELD_PREP(SSD130X_PAGE_COL_START_MASK, (val) >> 4)
68 #define SSD130X_PAGE_COL_START_LOW_SET(val) FIELD_PREP(SSD130X_PAGE_COL_START_MASK, (val))
69 #define SSD130X_START_PAGE_ADDRESS_MASK GENMASK(2, 0)
70 #define SSD130X_START_PAGE_ADDRESS_SET(val) FIELD_PREP(SSD130X_START_PAGE_ADDRESS_MASK, (val))
71 #define SSD130X_SET_SEG_REMAP_MASK GENMASK(0, 0)
72 #define SSD130X_SET_SEG_REMAP_SET(val) FIELD_PREP(SSD130X_SET_SEG_REMAP_MASK, (val))
73 #define SSD130X_SET_COM_SCAN_DIR_MASK GENMASK(3, 3)
74 #define SSD130X_SET_COM_SCAN_DIR_SET(val) FIELD_PREP(SSD130X_SET_COM_SCAN_DIR_MASK, (val))
75 #define SSD130X_SET_CLOCK_DIV_MASK GENMASK(3, 0)
76 #define SSD130X_SET_CLOCK_DIV_SET(val) FIELD_PREP(SSD130X_SET_CLOCK_DIV_MASK, (val))
77 #define SSD130X_SET_CLOCK_FREQ_MASK GENMASK(7, 4)
78 #define SSD130X_SET_CLOCK_FREQ_SET(val) FIELD_PREP(SSD130X_SET_CLOCK_FREQ_MASK, (val))
79 #define SSD130X_SET_PRECHARGE_PERIOD1_MASK GENMASK(3, 0)
80 #define SSD130X_SET_PRECHARGE_PERIOD1_SET(val) FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD1_MASK, (val))
81 #define SSD130X_SET_PRECHARGE_PERIOD2_MASK GENMASK(7, 4)
82 #define SSD130X_SET_PRECHARGE_PERIOD2_SET(val) FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD2_MASK, (val))
83 #define SSD130X_SET_COM_PINS_CONFIG1_MASK GENMASK(4, 4)
84 #define SSD130X_SET_COM_PINS_CONFIG1_SET(val) FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG1_MASK, (val))
85 #define SSD130X_SET_COM_PINS_CONFIG2_MASK GENMASK(5, 5)
86 #define SSD130X_SET_COM_PINS_CONFIG2_SET(val) FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG2_MASK, (val))
88 #define SSD130X_SET_ADDRESS_MODE_HORIZONTAL 0x00
89 #define SSD130X_SET_ADDRESS_MODE_VERTICAL 0x01
90 #define SSD130X_SET_ADDRESS_MODE_PAGE 0x02
92 #define SSD130X_SET_AREA_COLOR_MODE_ENABLE 0x1e
93 #define SSD130X_SET_AREA_COLOR_MODE_LOW_POWER 0x05
95 #define MAX_CONTRAST 255
97 const struct ssd130x_deviceinfo ssd130x_variants[] = {
99 .default_vcomh = 0x40,
100 .default_dclk_div = 1,
101 .default_dclk_frq = 5,
105 .default_vcomh = 0x34,
106 .default_dclk_div = 1,
107 .default_dclk_frq = 7,
110 .default_vcomh = 0x20,
111 .default_dclk_div = 1,
112 .default_dclk_frq = 8,
113 .need_chargepump = 1,
116 .default_vcomh = 0x20,
117 .default_dclk_div = 2,
118 .default_dclk_frq = 12,
122 .default_vcomh = 0x34,
123 .default_dclk_div = 1,
124 .default_dclk_frq = 10,
127 EXPORT_SYMBOL_NS_GPL(ssd130x_variants, DRM_SSD130X);
129 static inline struct ssd130x_device *drm_to_ssd130x(struct drm_device *drm)
131 return container_of(drm, struct ssd130x_device, drm);
135 * Helper to write data (SSD130X_DATA) to the device.
137 static int ssd130x_write_data(struct ssd130x_device *ssd130x, u8 *values, int count)
139 return regmap_bulk_write(ssd130x->regmap, SSD130X_DATA, values, count);
143 * Helper to write command (SSD130X_COMMAND). The fist variadic argument
144 * is the command to write and the following are the command options.
146 * Note that the ssd130x protocol requires each command and option to be
147 * written as a SSD130X_COMMAND device register value. That is why a call
148 * to regmap_write(..., SSD130X_COMMAND, ...) is done for each argument.
150 static int ssd130x_write_cmd(struct ssd130x_device *ssd130x, int count,
151 /* u8 cmd, u8 option, ... */...)
160 value = va_arg(ap, int);
161 ret = regmap_write(ssd130x->regmap, SSD130X_COMMAND, value);
172 /* Set address range for horizontal/vertical addressing modes */
173 static int ssd130x_set_col_range(struct ssd130x_device *ssd130x,
174 u8 col_start, u8 cols)
176 u8 col_end = col_start + cols - 1;
179 if (col_start == ssd130x->col_start && col_end == ssd130x->col_end)
182 ret = ssd130x_write_cmd(ssd130x, 3, SSD130X_SET_COL_RANGE, col_start, col_end);
186 ssd130x->col_start = col_start;
187 ssd130x->col_end = col_end;
191 static int ssd130x_set_page_range(struct ssd130x_device *ssd130x,
192 u8 page_start, u8 pages)
194 u8 page_end = page_start + pages - 1;
197 if (page_start == ssd130x->page_start && page_end == ssd130x->page_end)
200 ret = ssd130x_write_cmd(ssd130x, 3, SSD130X_SET_PAGE_RANGE, page_start, page_end);
204 ssd130x->page_start = page_start;
205 ssd130x->page_end = page_end;
209 /* Set page and column start address for page addressing mode */
210 static int ssd130x_set_page_pos(struct ssd130x_device *ssd130x,
211 u8 page_start, u8 col_start)
214 u32 page, col_low, col_high;
216 page = SSD130X_START_PAGE_ADDRESS |
217 SSD130X_START_PAGE_ADDRESS_SET(page_start);
218 col_low = SSD130X_PAGE_COL_START_LOW |
219 SSD130X_PAGE_COL_START_LOW_SET(col_start);
220 col_high = SSD130X_PAGE_COL_START_HIGH |
221 SSD130X_PAGE_COL_START_HIGH_SET(col_start);
222 ret = ssd130x_write_cmd(ssd130x, 3, page, col_low, col_high);
229 static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x)
231 struct device *dev = ssd130x->dev;
232 struct pwm_state pwmstate;
234 ssd130x->pwm = pwm_get(dev, NULL);
235 if (IS_ERR(ssd130x->pwm)) {
236 dev_err(dev, "Could not get PWM from firmware description!\n");
237 return PTR_ERR(ssd130x->pwm);
240 pwm_init_state(ssd130x->pwm, &pwmstate);
241 pwm_set_relative_duty_cycle(&pwmstate, 50, 100);
242 pwm_apply_state(ssd130x->pwm, &pwmstate);
245 pwm_enable(ssd130x->pwm);
247 dev_dbg(dev, "Using PWM%d with a %lluns period.\n",
248 ssd130x->pwm->pwm, pwm_get_period(ssd130x->pwm));
253 static void ssd130x_reset(struct ssd130x_device *ssd130x)
258 /* Reset the screen */
259 gpiod_set_value_cansleep(ssd130x->reset, 1);
261 gpiod_set_value_cansleep(ssd130x->reset, 0);
265 static int ssd130x_power_on(struct ssd130x_device *ssd130x)
267 struct device *dev = ssd130x->dev;
270 ssd130x_reset(ssd130x);
272 ret = regulator_enable(ssd130x->vcc_reg);
274 dev_err(dev, "Failed to enable VCC: %d\n", ret);
278 if (ssd130x->device_info->need_pwm) {
279 ret = ssd130x_pwm_enable(ssd130x);
281 dev_err(dev, "Failed to enable PWM: %d\n", ret);
282 regulator_disable(ssd130x->vcc_reg);
290 static void ssd130x_power_off(struct ssd130x_device *ssd130x)
292 pwm_disable(ssd130x->pwm);
293 pwm_put(ssd130x->pwm);
295 regulator_disable(ssd130x->vcc_reg);
298 static int ssd130x_init(struct ssd130x_device *ssd130x)
300 u32 precharge, dclk, com_invdir, compins, chargepump, seg_remap;
304 /* Set initial contrast */
305 ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_CONTRAST, ssd130x->contrast);
309 /* Set segment re-map */
310 seg_remap = (SSD130X_SET_SEG_REMAP |
311 SSD130X_SET_SEG_REMAP_SET(ssd130x->seg_remap));
312 ret = ssd130x_write_cmd(ssd130x, 1, seg_remap);
316 /* Set COM direction */
317 com_invdir = (SSD130X_SET_COM_SCAN_DIR |
318 SSD130X_SET_COM_SCAN_DIR_SET(ssd130x->com_invdir));
319 ret = ssd130x_write_cmd(ssd130x, 1, com_invdir);
323 /* Set multiplex ratio value */
324 ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_MULTIPLEX_RATIO, ssd130x->height - 1);
328 /* set display offset value */
329 ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_DISPLAY_OFFSET, ssd130x->com_offset);
333 /* Set clock frequency */
334 dclk = (SSD130X_SET_CLOCK_DIV_SET(ssd130x->dclk_div - 1) |
335 SSD130X_SET_CLOCK_FREQ_SET(ssd130x->dclk_frq));
336 ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_CLOCK_FREQ, dclk);
340 /* Set Area Color Mode ON/OFF & Low Power Display Mode */
341 if (ssd130x->area_color_enable || ssd130x->low_power) {
344 if (ssd130x->area_color_enable)
345 mode |= SSD130X_SET_AREA_COLOR_MODE_ENABLE;
347 if (ssd130x->low_power)
348 mode |= SSD130X_SET_AREA_COLOR_MODE_LOW_POWER;
350 ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_AREA_COLOR_MODE, mode);
355 /* Set precharge period in number of ticks from the internal clock */
356 precharge = (SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep1) |
357 SSD130X_SET_PRECHARGE_PERIOD2_SET(ssd130x->prechargep2));
358 ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_PRECHARGE_PERIOD, precharge);
362 /* Set COM pins configuration */
365 * The COM scan mode field values are the inverse of the boolean DT
366 * property "solomon,com-seq". The value 0b means scan from COM0 to
367 * COM[N - 1] while 1b means scan from COM[N - 1] to COM0.
369 scan_mode = !ssd130x->com_seq;
370 compins |= (SSD130X_SET_COM_PINS_CONFIG1_SET(scan_mode) |
371 SSD130X_SET_COM_PINS_CONFIG2_SET(ssd130x->com_lrremap));
372 ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_COM_PINS_CONFIG, compins);
377 ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_VCOMH, ssd130x->vcomh);
381 /* Turn on the DC-DC Charge Pump */
384 if (ssd130x->device_info->need_chargepump)
385 chargepump |= BIT(2);
387 ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_CHARGE_PUMP, chargepump);
391 /* Set lookup table */
392 if (ssd130x->lookup_table_set) {
395 ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_SET_LOOKUP_TABLE);
399 for (i = 0; i < ARRAY_SIZE(ssd130x->lookup_table); i++) {
400 u8 val = ssd130x->lookup_table[i];
402 if (val < 31 || val > 63)
403 dev_warn(ssd130x->dev,
404 "lookup table index %d value out of range 31 <= %d <= 63\n",
406 ret = ssd130x_write_cmd(ssd130x, 1, val);
412 /* Switch to page addressing mode */
413 if (ssd130x->page_address_mode)
414 return ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_ADDRESS_MODE,
415 SSD130X_SET_ADDRESS_MODE_PAGE);
417 /* Switch to horizontal addressing mode */
418 return ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_ADDRESS_MODE,
419 SSD130X_SET_ADDRESS_MODE_HORIZONTAL);
422 static int ssd130x_update_rect(struct ssd130x_device *ssd130x, u8 *buf,
423 struct drm_rect *rect)
425 unsigned int x = rect->x1;
426 unsigned int y = rect->y1;
427 unsigned int width = drm_rect_width(rect);
428 unsigned int height = drm_rect_height(rect);
429 unsigned int line_length = DIV_ROUND_UP(width, 8);
430 unsigned int pages = DIV_ROUND_UP(height, 8);
431 struct drm_device *drm = &ssd130x->drm;
434 u8 *data_array = NULL;
436 drm_WARN_ONCE(drm, y % 8 != 0, "y must be aligned to screen page\n");
438 data_array = kcalloc(width, pages, GFP_KERNEL);
443 * The screen is divided in pages, each having a height of 8
444 * pixels, and the width of the screen. When sending a byte of
445 * data to the controller, it gives the 8 bits for the current
446 * column. I.e, the first byte are the 8 bits of the first
447 * column, then the 8 bits for the second column, etc.
450 * Representation of the screen, assuming it is 5 bits
451 * wide. Each letter-number combination is a bit that controls
463 * If you want to update this screen, you need to send 5 bytes:
464 * (1) A0 B0 C0 D0 E0 F0 G0 H0
465 * (2) A1 B1 C1 D1 E1 F1 G1 H1
466 * (3) A2 B2 C2 D2 E2 F2 G2 H2
467 * (4) A3 B3 C3 D3 E3 F3 G3 H3
468 * (5) A4 B4 C4 D4 E4 F4 G4 H4
471 if (!ssd130x->page_address_mode) {
472 /* Set address range for horizontal addressing mode */
473 ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset + x, width);
477 ret = ssd130x_set_page_range(ssd130x, ssd130x->page_offset + y / 8, pages);
482 for (i = 0; i < pages; i++) {
485 /* Last page may be partial */
486 if (8 * (y / 8 + i + 1) > ssd130x->height)
487 m = ssd130x->height % 8;
488 for (j = 0; j < width; j++) {
491 for (k = 0; k < m; k++) {
492 u8 byte = buf[(8 * i + k) * line_length + j / 8];
493 u8 bit = (byte >> (j % 8)) & 1;
497 data_array[array_idx++] = data;
501 * In page addressing mode, the start address needs to be reset,
502 * and each page then needs to be written out separately.
504 if (ssd130x->page_address_mode) {
505 ret = ssd130x_set_page_pos(ssd130x,
506 ssd130x->page_offset + i,
507 ssd130x->col_offset + x);
511 ret = ssd130x_write_data(ssd130x, data_array, width);
519 /* Write out update in one go if we aren't using page addressing mode */
520 if (!ssd130x->page_address_mode)
521 ret = ssd130x_write_data(ssd130x, data_array, width * pages);
528 static void ssd130x_clear_screen(struct ssd130x_device *ssd130x)
531 struct drm_rect fullscreen = {
533 .x2 = ssd130x->width,
535 .y2 = ssd130x->height,
538 buf = kcalloc(DIV_ROUND_UP(ssd130x->width, 8), ssd130x->height,
543 ssd130x_update_rect(ssd130x, buf, &fullscreen);
548 static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_map *vmap,
549 struct drm_rect *rect)
551 struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);
552 struct iosys_map dst;
553 unsigned int dst_pitch;
557 /* Align y to display page boundaries */
558 rect->y1 = round_down(rect->y1, 8);
559 rect->y2 = min_t(unsigned int, round_up(rect->y2, 8), ssd130x->height);
561 dst_pitch = DIV_ROUND_UP(drm_rect_width(rect), 8);
562 buf = kcalloc(dst_pitch, drm_rect_height(rect), GFP_KERNEL);
566 ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
570 iosys_map_set_vaddr(&dst, buf);
571 drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect);
573 drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
575 ssd130x_update_rect(ssd130x, buf, rect);
583 static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane,
584 struct drm_atomic_state *state)
586 struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
587 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
588 struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
589 struct drm_atomic_helper_damage_iter iter;
590 struct drm_device *drm = plane->dev;
591 struct drm_rect dst_clip;
592 struct drm_rect damage;
595 if (!drm_dev_enter(drm, &idx))
598 drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
599 drm_atomic_for_each_plane_damage(&iter, &damage) {
600 dst_clip = plane_state->dst;
602 if (!drm_rect_intersect(&dst_clip, &damage))
605 ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip);
611 static void ssd130x_primary_plane_helper_atomic_disable(struct drm_plane *plane,
612 struct drm_atomic_state *state)
614 struct drm_device *drm = plane->dev;
615 struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
618 if (!drm_dev_enter(drm, &idx))
621 ssd130x_clear_screen(ssd130x);
626 static const struct drm_plane_helper_funcs ssd130x_primary_plane_helper_funcs = {
627 DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
628 .atomic_check = drm_plane_helper_atomic_check,
629 .atomic_update = ssd130x_primary_plane_helper_atomic_update,
630 .atomic_disable = ssd130x_primary_plane_helper_atomic_disable,
633 static const struct drm_plane_funcs ssd130x_primary_plane_funcs = {
634 .update_plane = drm_atomic_helper_update_plane,
635 .disable_plane = drm_atomic_helper_disable_plane,
636 .destroy = drm_plane_cleanup,
637 DRM_GEM_SHADOW_PLANE_FUNCS,
640 static enum drm_mode_status ssd130x_crtc_helper_mode_valid(struct drm_crtc *crtc,
641 const struct drm_display_mode *mode)
643 struct ssd130x_device *ssd130x = drm_to_ssd130x(crtc->dev);
645 if (mode->hdisplay != ssd130x->mode.hdisplay &&
646 mode->vdisplay != ssd130x->mode.vdisplay)
647 return MODE_ONE_SIZE;
648 else if (mode->hdisplay != ssd130x->mode.hdisplay)
649 return MODE_ONE_WIDTH;
650 else if (mode->vdisplay != ssd130x->mode.vdisplay)
651 return MODE_ONE_HEIGHT;
657 * The CRTC is always enabled. Screen updates are performed by
658 * the primary plane's atomic_update function. Disabling clears
659 * the screen in the primary plane's atomic_disable function.
661 static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs = {
662 .mode_valid = ssd130x_crtc_helper_mode_valid,
663 .atomic_check = drm_crtc_helper_atomic_check,
666 static const struct drm_crtc_funcs ssd130x_crtc_funcs = {
667 .reset = drm_atomic_helper_crtc_reset,
668 .destroy = drm_crtc_cleanup,
669 .set_config = drm_atomic_helper_set_config,
670 .page_flip = drm_atomic_helper_page_flip,
671 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
672 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
675 static void ssd130x_encoder_helper_atomic_enable(struct drm_encoder *encoder,
676 struct drm_atomic_state *state)
678 struct drm_device *drm = encoder->dev;
679 struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
682 ret = ssd130x_power_on(ssd130x);
686 ret = ssd130x_init(ssd130x);
688 ssd130x_power_off(ssd130x);
692 ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_ON);
694 backlight_enable(ssd130x->bl_dev);
697 static void ssd130x_encoder_helper_atomic_disable(struct drm_encoder *encoder,
698 struct drm_atomic_state *state)
700 struct drm_device *drm = encoder->dev;
701 struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
703 backlight_disable(ssd130x->bl_dev);
705 ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_OFF);
707 ssd130x_power_off(ssd130x);
710 static const struct drm_encoder_helper_funcs ssd130x_encoder_helper_funcs = {
711 .atomic_enable = ssd130x_encoder_helper_atomic_enable,
712 .atomic_disable = ssd130x_encoder_helper_atomic_disable,
715 static const struct drm_encoder_funcs ssd130x_encoder_funcs = {
716 .destroy = drm_encoder_cleanup,
719 static int ssd130x_connector_helper_get_modes(struct drm_connector *connector)
721 struct ssd130x_device *ssd130x = drm_to_ssd130x(connector->dev);
722 struct drm_display_mode *mode;
723 struct device *dev = ssd130x->dev;
725 mode = drm_mode_duplicate(connector->dev, &ssd130x->mode);
727 dev_err(dev, "Failed to duplicated mode\n");
731 drm_mode_probed_add(connector, mode);
732 drm_set_preferred_mode(connector, mode->hdisplay, mode->vdisplay);
734 /* There is only a single mode */
738 static const struct drm_connector_helper_funcs ssd130x_connector_helper_funcs = {
739 .get_modes = ssd130x_connector_helper_get_modes,
742 static const struct drm_connector_funcs ssd130x_connector_funcs = {
743 .reset = drm_atomic_helper_connector_reset,
744 .fill_modes = drm_helper_probe_single_connector_modes,
745 .destroy = drm_connector_cleanup,
746 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
747 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
750 static const struct drm_mode_config_funcs ssd130x_mode_config_funcs = {
751 .fb_create = drm_gem_fb_create_with_dirty,
752 .atomic_check = drm_atomic_helper_check,
753 .atomic_commit = drm_atomic_helper_commit,
756 static const uint32_t ssd130x_formats[] = {
760 DEFINE_DRM_GEM_FOPS(ssd130x_fops);
762 static const struct drm_driver ssd130x_drm_driver = {
763 DRM_GEM_SHMEM_DRIVER_OPS,
767 .major = DRIVER_MAJOR,
768 .minor = DRIVER_MINOR,
769 .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
770 .fops = &ssd130x_fops,
773 static int ssd130x_update_bl(struct backlight_device *bdev)
775 struct ssd130x_device *ssd130x = bl_get_data(bdev);
776 int brightness = backlight_get_brightness(bdev);
779 ssd130x->contrast = brightness;
781 ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_CONTRAST);
785 ret = ssd130x_write_cmd(ssd130x, 1, ssd130x->contrast);
792 static const struct backlight_ops ssd130xfb_bl_ops = {
793 .update_status = ssd130x_update_bl,
796 static void ssd130x_parse_properties(struct ssd130x_device *ssd130x)
798 struct device *dev = ssd130x->dev;
800 if (device_property_read_u32(dev, "solomon,width", &ssd130x->width))
803 if (device_property_read_u32(dev, "solomon,height", &ssd130x->height))
804 ssd130x->height = 16;
806 if (device_property_read_u32(dev, "solomon,page-offset", &ssd130x->page_offset))
807 ssd130x->page_offset = 1;
809 if (device_property_read_u32(dev, "solomon,col-offset", &ssd130x->col_offset))
810 ssd130x->col_offset = 0;
812 if (device_property_read_u32(dev, "solomon,com-offset", &ssd130x->com_offset))
813 ssd130x->com_offset = 0;
815 if (device_property_read_u32(dev, "solomon,prechargep1", &ssd130x->prechargep1))
816 ssd130x->prechargep1 = 2;
818 if (device_property_read_u32(dev, "solomon,prechargep2", &ssd130x->prechargep2))
819 ssd130x->prechargep2 = 2;
821 if (!device_property_read_u8_array(dev, "solomon,lookup-table",
822 ssd130x->lookup_table,
823 ARRAY_SIZE(ssd130x->lookup_table)))
824 ssd130x->lookup_table_set = 1;
826 ssd130x->seg_remap = !device_property_read_bool(dev, "solomon,segment-no-remap");
827 ssd130x->com_seq = device_property_read_bool(dev, "solomon,com-seq");
828 ssd130x->com_lrremap = device_property_read_bool(dev, "solomon,com-lrremap");
829 ssd130x->com_invdir = device_property_read_bool(dev, "solomon,com-invdir");
830 ssd130x->area_color_enable =
831 device_property_read_bool(dev, "solomon,area-color-enable");
832 ssd130x->low_power = device_property_read_bool(dev, "solomon,low-power");
834 ssd130x->contrast = 127;
835 ssd130x->vcomh = ssd130x->device_info->default_vcomh;
837 /* Setup display timing */
838 if (device_property_read_u32(dev, "solomon,dclk-div", &ssd130x->dclk_div))
839 ssd130x->dclk_div = ssd130x->device_info->default_dclk_div;
840 if (device_property_read_u32(dev, "solomon,dclk-frq", &ssd130x->dclk_frq))
841 ssd130x->dclk_frq = ssd130x->device_info->default_dclk_frq;
844 static int ssd130x_init_modeset(struct ssd130x_device *ssd130x)
846 struct drm_display_mode *mode = &ssd130x->mode;
847 struct device *dev = ssd130x->dev;
848 struct drm_device *drm = &ssd130x->drm;
849 unsigned long max_width, max_height;
850 struct drm_plane *primary_plane;
851 struct drm_crtc *crtc;
852 struct drm_encoder *encoder;
853 struct drm_connector *connector;
860 ret = drmm_mode_config_init(drm);
862 dev_err(dev, "DRM mode config init failed: %d\n", ret);
866 mode->type = DRM_MODE_TYPE_DRIVER;
868 mode->hdisplay = mode->htotal = ssd130x->width;
869 mode->hsync_start = mode->hsync_end = ssd130x->width;
870 mode->vdisplay = mode->vtotal = ssd130x->height;
871 mode->vsync_start = mode->vsync_end = ssd130x->height;
873 mode->height_mm = 27;
875 max_width = max_t(unsigned long, mode->hdisplay, DRM_SHADOW_PLANE_MAX_WIDTH);
876 max_height = max_t(unsigned long, mode->vdisplay, DRM_SHADOW_PLANE_MAX_HEIGHT);
878 drm->mode_config.min_width = mode->hdisplay;
879 drm->mode_config.max_width = max_width;
880 drm->mode_config.min_height = mode->vdisplay;
881 drm->mode_config.max_height = max_height;
882 drm->mode_config.preferred_depth = 24;
883 drm->mode_config.funcs = &ssd130x_mode_config_funcs;
887 primary_plane = &ssd130x->primary_plane;
888 ret = drm_universal_plane_init(drm, primary_plane, 0, &ssd130x_primary_plane_funcs,
889 ssd130x_formats, ARRAY_SIZE(ssd130x_formats),
890 NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
892 dev_err(dev, "DRM primary plane init failed: %d\n", ret);
896 drm_plane_helper_add(primary_plane, &ssd130x_primary_plane_helper_funcs);
898 drm_plane_enable_fb_damage_clips(primary_plane);
902 crtc = &ssd130x->crtc;
903 ret = drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
904 &ssd130x_crtc_funcs, NULL);
906 dev_err(dev, "DRM crtc init failed: %d\n", ret);
910 drm_crtc_helper_add(crtc, &ssd130x_crtc_helper_funcs);
914 encoder = &ssd130x->encoder;
915 ret = drm_encoder_init(drm, encoder, &ssd130x_encoder_funcs,
916 DRM_MODE_ENCODER_NONE, NULL);
918 dev_err(dev, "DRM encoder init failed: %d\n", ret);
922 drm_encoder_helper_add(encoder, &ssd130x_encoder_helper_funcs);
924 encoder->possible_crtcs = drm_crtc_mask(crtc);
928 connector = &ssd130x->connector;
929 ret = drm_connector_init(drm, connector, &ssd130x_connector_funcs,
930 DRM_MODE_CONNECTOR_Unknown);
932 dev_err(dev, "DRM connector init failed: %d\n", ret);
936 drm_connector_helper_add(connector, &ssd130x_connector_helper_funcs);
938 ret = drm_connector_attach_encoder(connector, encoder);
940 dev_err(dev, "DRM attach connector to encoder failed: %d\n", ret);
944 drm_mode_config_reset(drm);
949 static int ssd130x_get_resources(struct ssd130x_device *ssd130x)
951 struct device *dev = ssd130x->dev;
953 ssd130x->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
954 if (IS_ERR(ssd130x->reset))
955 return dev_err_probe(dev, PTR_ERR(ssd130x->reset),
956 "Failed to get reset gpio\n");
958 ssd130x->vcc_reg = devm_regulator_get(dev, "vcc");
959 if (IS_ERR(ssd130x->vcc_reg))
960 return dev_err_probe(dev, PTR_ERR(ssd130x->vcc_reg),
961 "Failed to get VCC regulator\n");
966 struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap)
968 struct ssd130x_device *ssd130x;
969 struct backlight_device *bl;
970 struct drm_device *drm;
973 ssd130x = devm_drm_dev_alloc(dev, &ssd130x_drm_driver,
974 struct ssd130x_device, drm);
976 return ERR_PTR(dev_err_probe(dev, PTR_ERR(ssd130x),
977 "Failed to allocate DRM device\n"));
982 ssd130x->regmap = regmap;
983 ssd130x->device_info = device_get_match_data(dev);
985 if (ssd130x->device_info->page_mode_only)
986 ssd130x->page_address_mode = 1;
988 ssd130x_parse_properties(ssd130x);
990 ret = ssd130x_get_resources(ssd130x);
994 bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
995 &ssd130xfb_bl_ops, NULL);
997 return ERR_PTR(dev_err_probe(dev, PTR_ERR(bl),
998 "Unable to register backlight device\n"));
1000 bl->props.brightness = ssd130x->contrast;
1001 bl->props.max_brightness = MAX_CONTRAST;
1002 ssd130x->bl_dev = bl;
1004 ret = ssd130x_init_modeset(ssd130x);
1006 return ERR_PTR(ret);
1008 ret = drm_dev_register(drm, 0);
1010 return ERR_PTR(dev_err_probe(dev, ret, "DRM device register failed\n"));
1012 drm_fbdev_generic_setup(drm, 32);
1016 EXPORT_SYMBOL_GPL(ssd130x_probe);
1018 void ssd130x_remove(struct ssd130x_device *ssd130x)
1020 drm_dev_unplug(&ssd130x->drm);
1022 EXPORT_SYMBOL_GPL(ssd130x_remove);
1024 void ssd130x_shutdown(struct ssd130x_device *ssd130x)
1026 drm_atomic_helper_shutdown(&ssd130x->drm);
1028 EXPORT_SYMBOL_GPL(ssd130x_shutdown);
1030 MODULE_DESCRIPTION(DRIVER_DESC);
1032 MODULE_LICENSE("GPL v2");