Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Driver for the Solomon SSD1307 OLED controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright 2012 Free Electrons
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/gpio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/property.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/pwm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/regulator/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #define SSD1307FB_DATA			0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #define SSD1307FB_COMMAND		0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #define SSD1307FB_SET_ADDRESS_MODE	0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL	(0x00)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #define SSD1307FB_SET_ADDRESS_MODE_VERTICAL	(0x01)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #define SSD1307FB_SET_ADDRESS_MODE_PAGE		(0x02)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #define SSD1307FB_SET_COL_RANGE		0x21
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #define SSD1307FB_SET_PAGE_RANGE	0x22
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #define SSD1307FB_CONTRAST		0x81
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #define SSD1307FB_SET_LOOKUP_TABLE	0x91
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #define	SSD1307FB_CHARGE_PUMP		0x8d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #define SSD1307FB_SEG_REMAP_ON		0xa1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #define SSD1307FB_DISPLAY_OFF		0xae
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #define SSD1307FB_SET_MULTIPLEX_RATIO	0xa8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #define SSD1307FB_DISPLAY_ON		0xaf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) #define SSD1307FB_START_PAGE_ADDRESS	0xb0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) #define SSD1307FB_SET_DISPLAY_OFFSET	0xd3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) #define	SSD1307FB_SET_CLOCK_FREQ	0xd5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) #define	SSD1307FB_SET_AREA_COLOR_MODE	0xd8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) #define	SSD1307FB_SET_PRECHARGE_PERIOD	0xd9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) #define	SSD1307FB_SET_COM_PINS_CONFIG	0xda
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) #define	SSD1307FB_SET_VCOMH		0xdb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) #define MAX_CONTRAST 255
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) #define REFRESHRATE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) static u_int refreshrate = REFRESHRATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) module_param(refreshrate, uint, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) struct ssd1307fb_deviceinfo {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	u32 default_vcomh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	u32 default_dclk_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	u32 default_dclk_frq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	int need_pwm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	int need_chargepump;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) struct ssd1307fb_par {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	unsigned area_color_enable : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	unsigned com_invdir : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	unsigned com_lrremap : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	unsigned com_seq : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	unsigned lookup_table_set : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	unsigned low_power : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	unsigned seg_remap : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	u32 com_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	u32 contrast;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	u32 dclk_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	u32 dclk_frq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	const struct ssd1307fb_deviceinfo *device_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	u32 height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	u8 lookup_table[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	u32 page_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	u32 col_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	u32 prechargep1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	u32 prechargep2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	struct pwm_device *pwm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	struct gpio_desc *reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	struct regulator *vbat_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	u32 vcomh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	u32 width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) struct ssd1307fb_array {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	u8	type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	u8	data[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) static const struct fb_fix_screeninfo ssd1307fb_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	.id		= "Solomon SSD1307",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	.type		= FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	.visual		= FB_VISUAL_MONO10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	.xpanstep	= 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	.ypanstep	= 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	.ywrapstep	= 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	.accel		= FB_ACCEL_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static const struct fb_var_screeninfo ssd1307fb_var = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	.bits_per_pixel	= 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	.red = { .length = 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	.green = { .length = 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	.blue = { .length = 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	struct ssd1307fb_array *array;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	array = kzalloc(sizeof(struct ssd1307fb_array) + len, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	if (!array)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	array->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	return array;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int ssd1307fb_write_array(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 				 struct ssd1307fb_array *array, u32 len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	len += sizeof(struct ssd1307fb_array);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	ret = i2c_master_send(client, (u8 *)array, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	if (ret != len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		dev_err(&client->dev, "Couldn't send I2C command.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	struct ssd1307fb_array *array;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	array = ssd1307fb_alloc_array(1, SSD1307FB_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	if (!array)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	array->data[0] = cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	ret = ssd1307fb_write_array(client, array, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	kfree(array);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) static void ssd1307fb_update_display(struct ssd1307fb_par *par)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	struct ssd1307fb_array *array;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	u8 *vmem = par->info->screen_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	unsigned int line_length = par->info->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	unsigned int pages = DIV_ROUND_UP(par->height, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	int i, j, k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	array = ssd1307fb_alloc_array(par->width * pages, SSD1307FB_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	if (!array)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	 * The screen is divided in pages, each having a height of 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	 * pixels, and the width of the screen. When sending a byte of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	 * data to the controller, it gives the 8 bits for the current
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	 * column. I.e, the first byte are the 8 bits of the first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	 * column, then the 8 bits for the second column, etc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	 * Representation of the screen, assuming it is 5 bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	 * wide. Each letter-number combination is a bit that controls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	 * one pixel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	 * A0 A1 A2 A3 A4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	 * B0 B1 B2 B3 B4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	 * C0 C1 C2 C3 C4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	 * D0 D1 D2 D3 D4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	 * E0 E1 E2 E3 E4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	 * F0 F1 F2 F3 F4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	 * G0 G1 G2 G3 G4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	 * H0 H1 H2 H3 H4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	 * If you want to update this screen, you need to send 5 bytes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	 *  (1) A0 B0 C0 D0 E0 F0 G0 H0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	 *  (2) A1 B1 C1 D1 E1 F1 G1 H1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	 *  (3) A2 B2 C2 D2 E2 F2 G2 H2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	 *  (4) A3 B3 C3 D3 E3 F3 G3 H3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	 *  (5) A4 B4 C4 D4 E4 F4 G4 H4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	for (i = 0; i < pages; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 		for (j = 0; j < par->width; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 			int m = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 			u32 array_idx = i * par->width + j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 			array->data[array_idx] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 			/* Last page may be partial */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 			if (i + 1 == pages && par->height % 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 				m = par->height % 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 			for (k = 0; k < m; k++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 				u8 byte = vmem[(8 * i + k) * line_length +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 					       j / 8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 				u8 bit = (byte >> (j % 8)) & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 				array->data[array_idx] |= bit << k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	ssd1307fb_write_array(par->client, array, par->width * pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	kfree(array);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static ssize_t ssd1307fb_write(struct fb_info *info, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 		size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	struct ssd1307fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	unsigned long total_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	unsigned long p = *ppos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	void *dst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	total_size = info->fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	if (p > total_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	if (count + p > total_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		count = total_size - p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	if (!count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	dst = info->screen_buffer + p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	if (copy_from_user(dst, buf, count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 		return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	ssd1307fb_update_display(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	*ppos += count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) static int ssd1307fb_blank(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	struct ssd1307fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	if (blank_mode != FB_BLANK_UNBLANK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 		return ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		return ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static void ssd1307fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	struct ssd1307fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	sys_fillrect(info, rect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	ssd1307fb_update_display(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) static void ssd1307fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	struct ssd1307fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	sys_copyarea(info, area);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	ssd1307fb_update_display(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static void ssd1307fb_imageblit(struct fb_info *info, const struct fb_image *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	struct ssd1307fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	sys_imageblit(info, image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 	ssd1307fb_update_display(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) static const struct fb_ops ssd1307fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	.owner		= THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	.fb_read	= fb_sys_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	.fb_write	= ssd1307fb_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	.fb_blank	= ssd1307fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	.fb_fillrect	= ssd1307fb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	.fb_copyarea	= ssd1307fb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	.fb_imageblit	= ssd1307fb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static void ssd1307fb_deferred_io(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 				struct list_head *pagelist)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	ssd1307fb_update_display(info->par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static int ssd1307fb_init(struct ssd1307fb_par *par)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	struct pwm_state pwmstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	u32 precharge, dclk, com_invdir, compins;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	if (par->device_info->need_pwm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 		par->pwm = pwm_get(&par->client->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 		if (IS_ERR(par->pwm)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 			dev_err(&par->client->dev, "Could not get PWM from device tree!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 			return PTR_ERR(par->pwm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 		pwm_init_state(par->pwm, &pwmstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		pwm_set_relative_duty_cycle(&pwmstate, 50, 100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		pwm_apply_state(par->pwm, &pwmstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 		/* Enable the PWM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 		pwm_enable(par->pwm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 		dev_dbg(&par->client->dev, "Using PWM%d with a %lluns period.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 			par->pwm->pwm, pwm_get_period(par->pwm));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	/* Set initial contrast */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	ret = ssd1307fb_write_cmd(par->client, par->contrast);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	/* Set segment re-map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	if (par->seg_remap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 		ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 		if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	/* Set COM direction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	com_invdir = 0xc0 | par->com_invdir << 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	ret = ssd1307fb_write_cmd(par->client,  com_invdir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	/* Set multiplex ratio value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	ret = ssd1307fb_write_cmd(par->client, par->height - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	/* set display offset value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	ret = ssd1307fb_write_cmd(par->client, par->com_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 	/* Set clock frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 	dclk = ((par->dclk_div - 1) & 0xf) | (par->dclk_frq & 0xf) << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 	ret = ssd1307fb_write_cmd(par->client, dclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 	/* Set Set Area Color Mode ON/OFF & Low Power Display Mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 	if (par->area_color_enable || par->low_power) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 		u32 mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 		ret = ssd1307fb_write_cmd(par->client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 					  SSD1307FB_SET_AREA_COLOR_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 		if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 		mode = (par->area_color_enable ? 0x30 : 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 			(par->low_power ? 5 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 		ret = ssd1307fb_write_cmd(par->client, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 		if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	/* Set precharge period in number of ticks from the internal clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	precharge = (par->prechargep1 & 0xf) | (par->prechargep2 & 0xf) << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 	ret = ssd1307fb_write_cmd(par->client, precharge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	/* Set COM pins configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	compins = 0x02 | !par->com_seq << 4 | par->com_lrremap << 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	ret = ssd1307fb_write_cmd(par->client, compins);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	/* Set VCOMH */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	ret = ssd1307fb_write_cmd(par->client, par->vcomh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	/* Turn on the DC-DC Charge Pump */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 	ret = ssd1307fb_write_cmd(par->client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 		BIT(4) | (par->device_info->need_chargepump ? BIT(2) : 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 	/* Set lookup table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 	if (par->lookup_table_set) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 		int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 		ret = ssd1307fb_write_cmd(par->client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 					  SSD1307FB_SET_LOOKUP_TABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 		if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 		for (i = 0; i < ARRAY_SIZE(par->lookup_table); ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 			u8 val = par->lookup_table[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 			if (val < 31 || val > 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 				dev_warn(&par->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 					 "lookup table index %d value out of range 31 <= %d <= 63\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 					 i, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 			ret = ssd1307fb_write_cmd(par->client, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 			if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 				return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	/* Switch to horizontal addressing mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 	ret = ssd1307fb_write_cmd(par->client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 				  SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	/* Set column range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 	ret = ssd1307fb_write_cmd(par->client, par->col_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	ret = ssd1307fb_write_cmd(par->client, par->col_offset + par->width - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	/* Set page range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 	ret = ssd1307fb_write_cmd(par->client, par->page_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	ret = ssd1307fb_write_cmd(par->client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 				  par->page_offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 				  DIV_ROUND_UP(par->height, 8) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	/* Clear the screen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	ssd1307fb_update_display(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 	/* Turn on the display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) static int ssd1307fb_update_bl(struct backlight_device *bdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 	struct ssd1307fb_par *par = bl_get_data(bdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 	int brightness = bdev->props.brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	par->contrast = brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	ret = ssd1307fb_write_cmd(par->client, par->contrast);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) static int ssd1307fb_get_brightness(struct backlight_device *bdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 	struct ssd1307fb_par *par = bl_get_data(bdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 	return par->contrast;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) static int ssd1307fb_check_fb(struct backlight_device *bdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 				   struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 	return (info->bl_dev == bdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) static const struct backlight_ops ssd1307fb_bl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 	.options	= BL_CORE_SUSPENDRESUME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 	.update_status	= ssd1307fb_update_bl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 	.get_brightness	= ssd1307fb_get_brightness,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	.check_fb	= ssd1307fb_check_fb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 	.default_vcomh = 0x34,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 	.default_dclk_div = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	.default_dclk_frq = 7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	.default_vcomh = 0x20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 	.default_dclk_div = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 	.default_dclk_frq = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 	.need_chargepump = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	.default_vcomh = 0x20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 	.default_dclk_div = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 	.default_dclk_frq = 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 	.need_pwm = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) static struct ssd1307fb_deviceinfo ssd1307fb_ssd1309_deviceinfo = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 	.default_vcomh = 0x34,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 	.default_dclk_div = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 	.default_dclk_frq = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) static const struct of_device_id ssd1307fb_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 		.compatible = "solomon,ssd1305fb-i2c",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 		.data = (void *)&ssd1307fb_ssd1305_deviceinfo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 		.compatible = "solomon,ssd1306fb-i2c",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 		.data = (void *)&ssd1307fb_ssd1306_deviceinfo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 		.compatible = "solomon,ssd1307fb-i2c",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 		.data = (void *)&ssd1307fb_ssd1307_deviceinfo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 		.compatible = "solomon,ssd1309fb-i2c",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 		.data = (void *)&ssd1307fb_ssd1309_deviceinfo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 	{},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) MODULE_DEVICE_TABLE(of, ssd1307fb_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static int ssd1307fb_probe(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 	struct device *dev = &client->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 	struct backlight_device *bl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 	char bl_name[12];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 	struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 	struct fb_deferred_io *ssd1307fb_defio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) 	u32 vmem_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 	struct ssd1307fb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) 	void *vmem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 	info = framebuffer_alloc(sizeof(struct ssd1307fb_par), dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 	if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 	par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 	par->info = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 	par->client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 	par->device_info = device_get_match_data(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	par->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 	if (IS_ERR(par->reset)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 		dev_err(dev, "failed to get reset gpio: %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 			PTR_ERR(par->reset));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 		ret = PTR_ERR(par->reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 		goto fb_alloc_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 	par->vbat_reg = devm_regulator_get_optional(dev, "vbat");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 	if (IS_ERR(par->vbat_reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 		ret = PTR_ERR(par->vbat_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 		if (ret == -ENODEV) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 			par->vbat_reg = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 			dev_err(dev, "failed to get VBAT regulator: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 			goto fb_alloc_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 	if (device_property_read_u32(dev, "solomon,width", &par->width))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 		par->width = 96;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 	if (device_property_read_u32(dev, "solomon,height", &par->height))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 		par->height = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 	if (device_property_read_u32(dev, "solomon,page-offset", &par->page_offset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) 		par->page_offset = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 	if (device_property_read_u32(dev, "solomon,col-offset", &par->col_offset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) 		par->col_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) 	if (device_property_read_u32(dev, "solomon,com-offset", &par->com_offset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 		par->com_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) 	if (device_property_read_u32(dev, "solomon,prechargep1", &par->prechargep1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 		par->prechargep1 = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) 	if (device_property_read_u32(dev, "solomon,prechargep2", &par->prechargep2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) 		par->prechargep2 = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) 	if (!device_property_read_u8_array(dev, "solomon,lookup-table",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 					   par->lookup_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 					   ARRAY_SIZE(par->lookup_table)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) 		par->lookup_table_set = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) 	par->seg_remap = !device_property_read_bool(dev, "solomon,segment-no-remap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 	par->com_seq = device_property_read_bool(dev, "solomon,com-seq");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 	par->com_lrremap = device_property_read_bool(dev, "solomon,com-lrremap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 	par->com_invdir = device_property_read_bool(dev, "solomon,com-invdir");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 	par->area_color_enable =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 		device_property_read_bool(dev, "solomon,area-color-enable");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 	par->low_power = device_property_read_bool(dev, "solomon,low-power");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 	par->contrast = 127;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 	par->vcomh = par->device_info->default_vcomh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 	/* Setup display timing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 	if (device_property_read_u32(dev, "solomon,dclk-div", &par->dclk_div))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 		par->dclk_div = par->device_info->default_dclk_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 	if (device_property_read_u32(dev, "solomon,dclk-frq", &par->dclk_frq))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 		par->dclk_frq = par->device_info->default_dclk_frq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 	vmem_size = DIV_ROUND_UP(par->width, 8) * par->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 	vmem = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 					get_order(vmem_size));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 	if (!vmem) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 		dev_err(dev, "Couldn't allocate graphical memory.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 		ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 		goto fb_alloc_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 	ssd1307fb_defio = devm_kzalloc(dev, sizeof(*ssd1307fb_defio),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 				       GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 	if (!ssd1307fb_defio) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 		dev_err(dev, "Couldn't allocate deferred io.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 		ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 		goto fb_alloc_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 	ssd1307fb_defio->delay = HZ / refreshrate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 	ssd1307fb_defio->deferred_io = ssd1307fb_deferred_io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) 	info->fbops = &ssd1307fb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 	info->fix = ssd1307fb_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 	info->fix.line_length = DIV_ROUND_UP(par->width, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 	info->fbdefio = ssd1307fb_defio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 	info->var = ssd1307fb_var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 	info->var.xres = par->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) 	info->var.xres_virtual = par->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 	info->var.yres = par->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 	info->var.yres_virtual = par->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 	info->screen_buffer = vmem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) 	info->fix.smem_start = __pa(vmem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 	info->fix.smem_len = vmem_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 	fb_deferred_io_init(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) 	i2c_set_clientdata(client, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) 	if (par->reset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) 		/* Reset the screen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) 		gpiod_set_value_cansleep(par->reset, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 		udelay(4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 		gpiod_set_value_cansleep(par->reset, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 		udelay(4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) 	if (par->vbat_reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 		ret = regulator_enable(par->vbat_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) 		if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) 			dev_err(dev, "failed to enable VBAT: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) 			goto reset_oled_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 	ret = ssd1307fb_init(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 		goto regulator_enable_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 	ret = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 		dev_err(dev, "Couldn't register the framebuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 		goto panel_init_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 	snprintf(bl_name, sizeof(bl_name), "ssd1307fb%d", info->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 	bl = backlight_device_register(bl_name, dev, par, &ssd1307fb_bl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 				       NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 	if (IS_ERR(bl)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 		ret = PTR_ERR(bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 		dev_err(dev, "unable to register backlight device: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 		goto bl_init_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 	bl->props.brightness = par->contrast;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) 	bl->props.max_brightness = MAX_CONTRAST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) 	info->bl_dev = bl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) 	dev_info(dev, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info->node, info->fix.id, vmem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) bl_init_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) 	unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) panel_init_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) 	if (par->device_info->need_pwm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) 		pwm_disable(par->pwm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) 		pwm_put(par->pwm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) regulator_enable_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) 	if (par->vbat_reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) 		regulator_disable(par->vbat_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) reset_oled_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) 	fb_deferred_io_cleanup(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) fb_alloc_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) 	framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) static int ssd1307fb_remove(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) 	struct fb_info *info = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) 	struct ssd1307fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) 	ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) 	backlight_device_unregister(info->bl_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) 	unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) 	if (par->device_info->need_pwm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) 		pwm_disable(par->pwm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) 		pwm_put(par->pwm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) 	if (par->vbat_reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) 		regulator_disable(par->vbat_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) 	fb_deferred_io_cleanup(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) 	__free_pages(__va(info->fix.smem_start), get_order(info->fix.smem_len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) 	framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) static const struct i2c_device_id ssd1307fb_i2c_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) 	{ "ssd1305fb", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) 	{ "ssd1306fb", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) 	{ "ssd1307fb", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) 	{ "ssd1309fb", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) 	{ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) static struct i2c_driver ssd1307fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) 	.probe_new = ssd1307fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) 	.remove = ssd1307fb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) 	.id_table = ssd1307fb_i2c_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) 	.driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) 		.name = "ssd1307fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) 		.of_match_table = ssd1307fb_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) module_i2c_driver(ssd1307fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) MODULE_DESCRIPTION("FB driver for the Solomon SSD1307 OLED controller");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) MODULE_LICENSE("GPL");