2 * Driver for the Solomon SSD1307 OLED controller
4 * Copyright 2012 Free Electrons
6 * Licensed under the GPLv2 or later.
9 #include <linux/module.h>
10 #include <linux/kernel.h>
11 #include <linux/i2c.h>
13 #include <linux/uaccess.h>
14 #include <linux/of_device.h>
15 #include <linux/of_gpio.h>
16 #include <linux/pwm.h>
17 #include <linux/delay.h>
19 #define SSD1307FB_WIDTH 96
20 #define SSD1307FB_HEIGHT 16
22 #define SSD1307FB_DATA 0x40
23 #define SSD1307FB_COMMAND 0x80
25 #define SSD1307FB_CONTRAST 0x81
26 #define SSD1307FB_SEG_REMAP_ON 0xa1
27 #define SSD1307FB_DISPLAY_OFF 0xae
28 #define SSD1307FB_DISPLAY_ON 0xaf
29 #define SSD1307FB_START_PAGE_ADDRESS 0xb0
31 struct ssd1307fb_par
{
32 struct i2c_client
*client
;
34 struct pwm_device
*pwm
;
39 static struct fb_fix_screeninfo ssd1307fb_fix
= {
40 .id
= "Solomon SSD1307",
41 .type
= FB_TYPE_PACKED_PIXELS
,
42 .visual
= FB_VISUAL_MONO10
,
46 .line_length
= SSD1307FB_WIDTH
/ 8,
47 .accel
= FB_ACCEL_NONE
,
50 static struct fb_var_screeninfo ssd1307fb_var
= {
51 .xres
= SSD1307FB_WIDTH
,
52 .yres
= SSD1307FB_HEIGHT
,
53 .xres_virtual
= SSD1307FB_WIDTH
,
54 .yres_virtual
= SSD1307FB_HEIGHT
,
58 static int ssd1307fb_write_array(struct i2c_client
*client
, u8 type
, u8
*cmd
, u32 len
)
63 buf
= kzalloc(len
+ 1, GFP_KERNEL
);
65 dev_err(&client
->dev
, "Couldn't allocate sending buffer.\n");
70 memcpy(buf
+ 1, cmd
, len
);
72 ret
= i2c_master_send(client
, buf
, len
+ 1);
74 dev_err(&client
->dev
, "Couldn't send I2C command.\n");
83 static inline int ssd1307fb_write_cmd_array(struct i2c_client
*client
, u8
*cmd
, u32 len
)
85 return ssd1307fb_write_array(client
, SSD1307FB_COMMAND
, cmd
, len
);
88 static inline int ssd1307fb_write_cmd(struct i2c_client
*client
, u8 cmd
)
90 return ssd1307fb_write_cmd_array(client
, &cmd
, 1);
93 static inline int ssd1307fb_write_data_array(struct i2c_client
*client
, u8
*cmd
, u32 len
)
95 return ssd1307fb_write_array(client
, SSD1307FB_DATA
, cmd
, len
);
98 static inline int ssd1307fb_write_data(struct i2c_client
*client
, u8 data
)
100 return ssd1307fb_write_data_array(client
, &data
, 1);
103 static void ssd1307fb_update_display(struct ssd1307fb_par
*par
)
105 u8
*vmem
= par
->info
->screen_base
;
109 * The screen is divided in pages, each having a height of 8
110 * pixels, and the width of the screen. When sending a byte of
111 * data to the controller, it gives the 8 bits for the current
112 * column. I.e, the first byte are the 8 bits of the first
113 * column, then the 8 bits for the second column, etc.
116 * Representation of the screen, assuming it is 5 bits
117 * wide. Each letter-number combination is a bit that controls
129 * If you want to update this screen, you need to send 5 bytes:
130 * (1) A0 B0 C0 D0 E0 F0 G0 H0
131 * (2) A1 B1 C1 D1 E1 F1 G1 H1
132 * (3) A2 B2 C2 D2 E2 F2 G2 H2
133 * (4) A3 B3 C3 D3 E3 F3 G3 H3
134 * (5) A4 B4 C4 D4 E4 F4 G4 H4
137 for (i
= 0; i
< (SSD1307FB_HEIGHT
/ 8); i
++) {
138 ssd1307fb_write_cmd(par
->client
, SSD1307FB_START_PAGE_ADDRESS
+ (i
+ 1));
139 ssd1307fb_write_cmd(par
->client
, 0x00);
140 ssd1307fb_write_cmd(par
->client
, 0x10);
142 for (j
= 0; j
< SSD1307FB_WIDTH
; j
++) {
144 for (k
= 0; k
< 8; k
++) {
145 u32 page_length
= SSD1307FB_WIDTH
* i
;
146 u32 index
= page_length
+ (SSD1307FB_WIDTH
* k
+ j
) / 8;
147 u8 byte
= *(vmem
+ index
);
148 u8 bit
= byte
& (1 << (j
% 8));
149 bit
= bit
>> (j
% 8);
152 ssd1307fb_write_data(par
->client
, buf
);
158 static ssize_t
ssd1307fb_write(struct fb_info
*info
, const char __user
*buf
,
159 size_t count
, loff_t
*ppos
)
161 struct ssd1307fb_par
*par
= info
->par
;
162 unsigned long total_size
;
163 unsigned long p
= *ppos
;
166 total_size
= info
->fix
.smem_len
;
171 if (count
+ p
> total_size
)
172 count
= total_size
- p
;
177 dst
= (void __force
*) (info
->screen_base
+ p
);
179 if (copy_from_user(dst
, buf
, count
))
182 ssd1307fb_update_display(par
);
189 static void ssd1307fb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
191 struct ssd1307fb_par
*par
= info
->par
;
192 sys_fillrect(info
, rect
);
193 ssd1307fb_update_display(par
);
196 static void ssd1307fb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
198 struct ssd1307fb_par
*par
= info
->par
;
199 sys_copyarea(info
, area
);
200 ssd1307fb_update_display(par
);
203 static void ssd1307fb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
205 struct ssd1307fb_par
*par
= info
->par
;
206 sys_imageblit(info
, image
);
207 ssd1307fb_update_display(par
);
210 static struct fb_ops ssd1307fb_ops
= {
211 .owner
= THIS_MODULE
,
212 .fb_read
= fb_sys_read
,
213 .fb_write
= ssd1307fb_write
,
214 .fb_fillrect
= ssd1307fb_fillrect
,
215 .fb_copyarea
= ssd1307fb_copyarea
,
216 .fb_imageblit
= ssd1307fb_imageblit
,
219 static void ssd1307fb_deferred_io(struct fb_info
*info
,
220 struct list_head
*pagelist
)
222 ssd1307fb_update_display(info
->par
);
225 static struct fb_deferred_io ssd1307fb_defio
= {
227 .deferred_io
= ssd1307fb_deferred_io
,
230 static int ssd1307fb_probe(struct i2c_client
*client
,
231 const struct i2c_device_id
*id
)
233 struct fb_info
*info
;
234 u32 vmem_size
= SSD1307FB_WIDTH
* SSD1307FB_HEIGHT
/ 8;
235 struct ssd1307fb_par
*par
;
239 if (!client
->dev
.of_node
) {
240 dev_err(&client
->dev
, "No device tree data found!\n");
244 info
= framebuffer_alloc(sizeof(struct ssd1307fb_par
), &client
->dev
);
246 dev_err(&client
->dev
, "Couldn't allocate framebuffer.\n");
250 vmem
= devm_kzalloc(&client
->dev
, vmem_size
, GFP_KERNEL
);
252 dev_err(&client
->dev
, "Couldn't allocate graphical memory.\n");
257 info
->fbops
= &ssd1307fb_ops
;
258 info
->fix
= ssd1307fb_fix
;
259 info
->fbdefio
= &ssd1307fb_defio
;
261 info
->var
= ssd1307fb_var
;
262 info
->var
.red
.length
= 1;
263 info
->var
.red
.offset
= 0;
264 info
->var
.green
.length
= 1;
265 info
->var
.green
.offset
= 0;
266 info
->var
.blue
.length
= 1;
267 info
->var
.blue
.offset
= 0;
269 info
->screen_base
= (u8 __force __iomem
*)vmem
;
270 info
->fix
.smem_start
= (unsigned long)vmem
;
271 info
->fix
.smem_len
= vmem_size
;
273 fb_deferred_io_init(info
);
277 par
->client
= client
;
279 par
->reset
= of_get_named_gpio(client
->dev
.of_node
,
281 if (!gpio_is_valid(par
->reset
)) {
283 goto reset_oled_error
;
286 ret
= devm_gpio_request_one(&client
->dev
, par
->reset
,
290 dev_err(&client
->dev
,
291 "failed to request gpio %d: %d\n",
293 goto reset_oled_error
;
296 par
->pwm
= pwm_get(&client
->dev
, NULL
);
297 if (IS_ERR(par
->pwm
)) {
298 dev_err(&client
->dev
, "Could not get PWM from device tree!\n");
299 ret
= PTR_ERR(par
->pwm
);
303 par
->pwm_period
= pwm_get_period(par
->pwm
);
305 dev_dbg(&client
->dev
, "Using PWM%d with a %dns period.\n", par
->pwm
->pwm
, par
->pwm_period
);
307 ret
= register_framebuffer(info
);
309 dev_err(&client
->dev
, "Couldn't register the framebuffer\n");
313 i2c_set_clientdata(client
, info
);
315 /* Reset the screen */
316 gpio_set_value(par
->reset
, 0);
318 gpio_set_value(par
->reset
, 1);
322 pwm_config(par
->pwm
, par
->pwm_period
/ 2, par
->pwm_period
);
323 pwm_enable(par
->pwm
);
325 /* Map column 127 of the OLED to segment 0 */
326 ret
= ssd1307fb_write_cmd(client
, SSD1307FB_SEG_REMAP_ON
);
328 dev_err(&client
->dev
, "Couldn't remap the screen.\n");
332 /* Turn on the display */
333 ret
= ssd1307fb_write_cmd(client
, SSD1307FB_DISPLAY_ON
);
335 dev_err(&client
->dev
, "Couldn't turn the display on.\n");
339 dev_info(&client
->dev
, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info
->node
, info
->fix
.id
, vmem_size
);
344 unregister_framebuffer(info
);
345 pwm_disable(par
->pwm
);
350 fb_deferred_io_cleanup(info
);
352 framebuffer_release(info
);
356 static int ssd1307fb_remove(struct i2c_client
*client
)
358 struct fb_info
*info
= i2c_get_clientdata(client
);
359 struct ssd1307fb_par
*par
= info
->par
;
361 unregister_framebuffer(info
);
362 pwm_disable(par
->pwm
);
364 fb_deferred_io_cleanup(info
);
365 framebuffer_release(info
);
370 static const struct i2c_device_id ssd1307fb_i2c_id
[] = {
374 MODULE_DEVICE_TABLE(i2c
, ssd1307fb_i2c_id
);
376 static const struct of_device_id ssd1307fb_of_match
[] = {
377 { .compatible
= "solomon,ssd1307fb-i2c" },
380 MODULE_DEVICE_TABLE(of
, ssd1307fb_of_match
);
382 static struct i2c_driver ssd1307fb_driver
= {
383 .probe
= ssd1307fb_probe
,
384 .remove
= ssd1307fb_remove
,
385 .id_table
= ssd1307fb_i2c_id
,
388 .of_match_table
= of_match_ptr(ssd1307fb_of_match
),
389 .owner
= THIS_MODULE
,
393 module_i2c_driver(ssd1307fb_driver
);
395 MODULE_DESCRIPTION("FB driver for the Solomon SSD1307 OLED controller");
396 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
397 MODULE_LICENSE("GPL");