xref: /OK3568_Linux_fs/kernel/drivers/video/backlight/hx8357.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Driver for the Himax HX-8357 LCD Controller
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2012 Free Electrons
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun #include <linux/lcd.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/of.h>
12*4882a593Smuzhiyun #include <linux/of_device.h>
13*4882a593Smuzhiyun #include <linux/of_gpio.h>
14*4882a593Smuzhiyun #include <linux/spi/spi.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define HX8357_NUM_IM_PINS	3
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #define HX8357_SWRESET			0x01
19*4882a593Smuzhiyun #define HX8357_GET_RED_CHANNEL		0x06
20*4882a593Smuzhiyun #define HX8357_GET_GREEN_CHANNEL	0x07
21*4882a593Smuzhiyun #define HX8357_GET_BLUE_CHANNEL		0x08
22*4882a593Smuzhiyun #define HX8357_GET_POWER_MODE		0x0a
23*4882a593Smuzhiyun #define HX8357_GET_MADCTL		0x0b
24*4882a593Smuzhiyun #define HX8357_GET_PIXEL_FORMAT		0x0c
25*4882a593Smuzhiyun #define HX8357_GET_DISPLAY_MODE		0x0d
26*4882a593Smuzhiyun #define HX8357_GET_SIGNAL_MODE		0x0e
27*4882a593Smuzhiyun #define HX8357_GET_DIAGNOSTIC_RESULT	0x0f
28*4882a593Smuzhiyun #define HX8357_ENTER_SLEEP_MODE		0x10
29*4882a593Smuzhiyun #define HX8357_EXIT_SLEEP_MODE		0x11
30*4882a593Smuzhiyun #define HX8357_ENTER_PARTIAL_MODE	0x12
31*4882a593Smuzhiyun #define HX8357_ENTER_NORMAL_MODE	0x13
32*4882a593Smuzhiyun #define HX8357_EXIT_INVERSION_MODE	0x20
33*4882a593Smuzhiyun #define HX8357_ENTER_INVERSION_MODE	0x21
34*4882a593Smuzhiyun #define HX8357_SET_DISPLAY_OFF		0x28
35*4882a593Smuzhiyun #define HX8357_SET_DISPLAY_ON		0x29
36*4882a593Smuzhiyun #define HX8357_SET_COLUMN_ADDRESS	0x2a
37*4882a593Smuzhiyun #define HX8357_SET_PAGE_ADDRESS		0x2b
38*4882a593Smuzhiyun #define HX8357_WRITE_MEMORY_START	0x2c
39*4882a593Smuzhiyun #define HX8357_READ_MEMORY_START	0x2e
40*4882a593Smuzhiyun #define HX8357_SET_PARTIAL_AREA		0x30
41*4882a593Smuzhiyun #define HX8357_SET_SCROLL_AREA		0x33
42*4882a593Smuzhiyun #define HX8357_SET_TEAR_OFF		0x34
43*4882a593Smuzhiyun #define HX8357_SET_TEAR_ON		0x35
44*4882a593Smuzhiyun #define HX8357_SET_ADDRESS_MODE		0x36
45*4882a593Smuzhiyun #define HX8357_SET_SCROLL_START		0x37
46*4882a593Smuzhiyun #define HX8357_EXIT_IDLE_MODE		0x38
47*4882a593Smuzhiyun #define HX8357_ENTER_IDLE_MODE		0x39
48*4882a593Smuzhiyun #define HX8357_SET_PIXEL_FORMAT		0x3a
49*4882a593Smuzhiyun #define HX8357_SET_PIXEL_FORMAT_DBI_3BIT	(0x1)
50*4882a593Smuzhiyun #define HX8357_SET_PIXEL_FORMAT_DBI_16BIT	(0x5)
51*4882a593Smuzhiyun #define HX8357_SET_PIXEL_FORMAT_DBI_18BIT	(0x6)
52*4882a593Smuzhiyun #define HX8357_SET_PIXEL_FORMAT_DPI_3BIT	(0x1 << 4)
53*4882a593Smuzhiyun #define HX8357_SET_PIXEL_FORMAT_DPI_16BIT	(0x5 << 4)
54*4882a593Smuzhiyun #define HX8357_SET_PIXEL_FORMAT_DPI_18BIT	(0x6 << 4)
55*4882a593Smuzhiyun #define HX8357_WRITE_MEMORY_CONTINUE	0x3c
56*4882a593Smuzhiyun #define HX8357_READ_MEMORY_CONTINUE	0x3e
57*4882a593Smuzhiyun #define HX8357_SET_TEAR_SCAN_LINES	0x44
58*4882a593Smuzhiyun #define HX8357_GET_SCAN_LINES		0x45
59*4882a593Smuzhiyun #define HX8357_READ_DDB_START		0xa1
60*4882a593Smuzhiyun #define HX8357_SET_DISPLAY_MODE		0xb4
61*4882a593Smuzhiyun #define HX8357_SET_DISPLAY_MODE_RGB_THROUGH	(0x3)
62*4882a593Smuzhiyun #define HX8357_SET_DISPLAY_MODE_RGB_INTERFACE	(1 << 4)
63*4882a593Smuzhiyun #define HX8357_SET_PANEL_DRIVING	0xc0
64*4882a593Smuzhiyun #define HX8357_SET_DISPLAY_FRAME	0xc5
65*4882a593Smuzhiyun #define HX8357_SET_RGB			0xc6
66*4882a593Smuzhiyun #define HX8357_SET_RGB_ENABLE_HIGH		(1 << 1)
67*4882a593Smuzhiyun #define HX8357_SET_GAMMA		0xc8
68*4882a593Smuzhiyun #define HX8357_SET_POWER		0xd0
69*4882a593Smuzhiyun #define HX8357_SET_VCOM			0xd1
70*4882a593Smuzhiyun #define HX8357_SET_POWER_NORMAL		0xd2
71*4882a593Smuzhiyun #define HX8357_SET_PANEL_RELATED	0xe9
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #define HX8369_SET_DISPLAY_BRIGHTNESS		0x51
74*4882a593Smuzhiyun #define HX8369_WRITE_CABC_DISPLAY_VALUE		0x53
75*4882a593Smuzhiyun #define HX8369_WRITE_CABC_BRIGHT_CTRL		0x55
76*4882a593Smuzhiyun #define HX8369_WRITE_CABC_MIN_BRIGHTNESS	0x5e
77*4882a593Smuzhiyun #define HX8369_SET_POWER			0xb1
78*4882a593Smuzhiyun #define HX8369_SET_DISPLAY_MODE			0xb2
79*4882a593Smuzhiyun #define HX8369_SET_DISPLAY_WAVEFORM_CYC		0xb4
80*4882a593Smuzhiyun #define HX8369_SET_VCOM				0xb6
81*4882a593Smuzhiyun #define HX8369_SET_EXTENSION_COMMAND		0xb9
82*4882a593Smuzhiyun #define HX8369_SET_GIP				0xd5
83*4882a593Smuzhiyun #define HX8369_SET_GAMMA_CURVE_RELATED		0xe0
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun struct hx8357_data {
86*4882a593Smuzhiyun 	unsigned		im_pins[HX8357_NUM_IM_PINS];
87*4882a593Smuzhiyun 	unsigned		reset;
88*4882a593Smuzhiyun 	struct spi_device	*spi;
89*4882a593Smuzhiyun 	int			state;
90*4882a593Smuzhiyun 	bool			use_im_pins;
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun static u8 hx8357_seq_power[] = {
94*4882a593Smuzhiyun 	HX8357_SET_POWER, 0x44, 0x41, 0x06,
95*4882a593Smuzhiyun };
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun static u8 hx8357_seq_vcom[] = {
98*4882a593Smuzhiyun 	HX8357_SET_VCOM, 0x40, 0x10,
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun static u8 hx8357_seq_power_normal[] = {
102*4882a593Smuzhiyun 	HX8357_SET_POWER_NORMAL, 0x05, 0x12,
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun static u8 hx8357_seq_panel_driving[] = {
106*4882a593Smuzhiyun 	HX8357_SET_PANEL_DRIVING, 0x14, 0x3b, 0x00, 0x02, 0x11,
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun static u8 hx8357_seq_display_frame[] = {
110*4882a593Smuzhiyun 	HX8357_SET_DISPLAY_FRAME, 0x0c,
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun static u8 hx8357_seq_panel_related[] = {
114*4882a593Smuzhiyun 	HX8357_SET_PANEL_RELATED, 0x01,
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun static u8 hx8357_seq_undefined1[] = {
118*4882a593Smuzhiyun 	0xea, 0x03, 0x00, 0x00,
119*4882a593Smuzhiyun };
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun static u8 hx8357_seq_undefined2[] = {
122*4882a593Smuzhiyun 	0xeb, 0x40, 0x54, 0x26, 0xdb,
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun static u8 hx8357_seq_gamma[] = {
126*4882a593Smuzhiyun 	HX8357_SET_GAMMA, 0x00, 0x15, 0x00, 0x22, 0x00,
127*4882a593Smuzhiyun 	0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00,
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun static u8 hx8357_seq_address_mode[] = {
131*4882a593Smuzhiyun 	HX8357_SET_ADDRESS_MODE, 0xc0,
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun static u8 hx8357_seq_pixel_format[] = {
135*4882a593Smuzhiyun 	HX8357_SET_PIXEL_FORMAT,
136*4882a593Smuzhiyun 	HX8357_SET_PIXEL_FORMAT_DPI_18BIT |
137*4882a593Smuzhiyun 	HX8357_SET_PIXEL_FORMAT_DBI_18BIT,
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun static u8 hx8357_seq_column_address[] = {
141*4882a593Smuzhiyun 	HX8357_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0x3f,
142*4882a593Smuzhiyun };
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun static u8 hx8357_seq_page_address[] = {
145*4882a593Smuzhiyun 	HX8357_SET_PAGE_ADDRESS, 0x00, 0x00, 0x01, 0xdf,
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun static u8 hx8357_seq_rgb[] = {
149*4882a593Smuzhiyun 	HX8357_SET_RGB, 0x02,
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun static u8 hx8357_seq_display_mode[] = {
153*4882a593Smuzhiyun 	HX8357_SET_DISPLAY_MODE,
154*4882a593Smuzhiyun 	HX8357_SET_DISPLAY_MODE_RGB_THROUGH |
155*4882a593Smuzhiyun 	HX8357_SET_DISPLAY_MODE_RGB_INTERFACE,
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun static u8 hx8369_seq_write_CABC_min_brightness[] = {
159*4882a593Smuzhiyun 	HX8369_WRITE_CABC_MIN_BRIGHTNESS, 0x00,
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun static u8 hx8369_seq_write_CABC_control[] = {
163*4882a593Smuzhiyun 	HX8369_WRITE_CABC_DISPLAY_VALUE, 0x24,
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun static u8 hx8369_seq_set_display_brightness[] = {
167*4882a593Smuzhiyun 	HX8369_SET_DISPLAY_BRIGHTNESS, 0xFF,
168*4882a593Smuzhiyun };
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun static u8 hx8369_seq_write_CABC_control_setting[] = {
171*4882a593Smuzhiyun 	HX8369_WRITE_CABC_BRIGHT_CTRL, 0x02,
172*4882a593Smuzhiyun };
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun static u8 hx8369_seq_extension_command[] = {
175*4882a593Smuzhiyun 	HX8369_SET_EXTENSION_COMMAND, 0xff, 0x83, 0x69,
176*4882a593Smuzhiyun };
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun static u8 hx8369_seq_display_related[] = {
179*4882a593Smuzhiyun 	HX8369_SET_DISPLAY_MODE, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00,
180*4882a593Smuzhiyun 	0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00,	0x01,
181*4882a593Smuzhiyun };
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun static u8 hx8369_seq_panel_waveform_cycle[] = {
184*4882a593Smuzhiyun 	HX8369_SET_DISPLAY_WAVEFORM_CYC, 0x0a, 0x1d, 0x80, 0x06, 0x02,
185*4882a593Smuzhiyun };
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun static u8 hx8369_seq_set_address_mode[] = {
188*4882a593Smuzhiyun 	HX8357_SET_ADDRESS_MODE, 0x00,
189*4882a593Smuzhiyun };
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun static u8 hx8369_seq_vcom[] = {
192*4882a593Smuzhiyun 	HX8369_SET_VCOM, 0x3e, 0x3e,
193*4882a593Smuzhiyun };
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun static u8 hx8369_seq_gip[] = {
196*4882a593Smuzhiyun 	HX8369_SET_GIP, 0x00, 0x01, 0x03, 0x25, 0x01, 0x02, 0x28, 0x70,
197*4882a593Smuzhiyun 	0x11, 0x13, 0x00, 0x00, 0x40, 0x26, 0x51, 0x37, 0x00, 0x00, 0x71,
198*4882a593Smuzhiyun 	0x35, 0x60, 0x24, 0x07, 0x0f, 0x04, 0x04,
199*4882a593Smuzhiyun };
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun static u8 hx8369_seq_power[] = {
202*4882a593Smuzhiyun 	HX8369_SET_POWER, 0x01, 0x00, 0x34, 0x03, 0x00, 0x11, 0x11, 0x32,
203*4882a593Smuzhiyun 	0x2f, 0x3f, 0x3f, 0x01, 0x3a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
204*4882a593Smuzhiyun };
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun static u8 hx8369_seq_gamma_curve_related[] = {
207*4882a593Smuzhiyun 	HX8369_SET_GAMMA_CURVE_RELATED, 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d,
208*4882a593Smuzhiyun 	0x2e, 0x4a, 0x08, 0x0e, 0x0f, 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
209*4882a593Smuzhiyun 	0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d, 0x2e, 0x4a, 0x08, 0x0e, 0x0f,
210*4882a593Smuzhiyun 	0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
211*4882a593Smuzhiyun };
212*4882a593Smuzhiyun 
hx8357_spi_write_then_read(struct lcd_device * lcdev,u8 * txbuf,u16 txlen,u8 * rxbuf,u16 rxlen)213*4882a593Smuzhiyun static int hx8357_spi_write_then_read(struct lcd_device *lcdev,
214*4882a593Smuzhiyun 				u8 *txbuf, u16 txlen,
215*4882a593Smuzhiyun 				u8 *rxbuf, u16 rxlen)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	struct hx8357_data *lcd = lcd_get_data(lcdev);
218*4882a593Smuzhiyun 	struct spi_message msg;
219*4882a593Smuzhiyun 	struct spi_transfer xfer[2];
220*4882a593Smuzhiyun 	u16 *local_txbuf = NULL;
221*4882a593Smuzhiyun 	int ret = 0;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	memset(xfer, 0, sizeof(xfer));
224*4882a593Smuzhiyun 	spi_message_init(&msg);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	if (txlen) {
227*4882a593Smuzhiyun 		int i;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 		local_txbuf = kcalloc(txlen, sizeof(*local_txbuf), GFP_KERNEL);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 		if (!local_txbuf)
232*4882a593Smuzhiyun 			return -ENOMEM;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 		for (i = 0; i < txlen; i++) {
235*4882a593Smuzhiyun 			local_txbuf[i] = txbuf[i];
236*4882a593Smuzhiyun 			if (i > 0)
237*4882a593Smuzhiyun 				local_txbuf[i] |= 1 << 8;
238*4882a593Smuzhiyun 		}
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 		xfer[0].len = 2 * txlen;
241*4882a593Smuzhiyun 		xfer[0].bits_per_word = 9;
242*4882a593Smuzhiyun 		xfer[0].tx_buf = local_txbuf;
243*4882a593Smuzhiyun 		spi_message_add_tail(&xfer[0], &msg);
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	if (rxlen) {
247*4882a593Smuzhiyun 		xfer[1].len = rxlen;
248*4882a593Smuzhiyun 		xfer[1].bits_per_word = 8;
249*4882a593Smuzhiyun 		xfer[1].rx_buf = rxbuf;
250*4882a593Smuzhiyun 		spi_message_add_tail(&xfer[1], &msg);
251*4882a593Smuzhiyun 	}
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	ret = spi_sync(lcd->spi, &msg);
254*4882a593Smuzhiyun 	if (ret < 0)
255*4882a593Smuzhiyun 		dev_err(&lcdev->dev, "Couldn't send SPI data\n");
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	if (txlen)
258*4882a593Smuzhiyun 		kfree(local_txbuf);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	return ret;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
hx8357_spi_write_array(struct lcd_device * lcdev,u8 * value,u8 len)263*4882a593Smuzhiyun static inline int hx8357_spi_write_array(struct lcd_device *lcdev,
264*4882a593Smuzhiyun 					u8 *value, u8 len)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	return hx8357_spi_write_then_read(lcdev, value, len, NULL, 0);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
hx8357_spi_write_byte(struct lcd_device * lcdev,u8 value)269*4882a593Smuzhiyun static inline int hx8357_spi_write_byte(struct lcd_device *lcdev,
270*4882a593Smuzhiyun 					u8 value)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	return hx8357_spi_write_then_read(lcdev, &value, 1, NULL, 0);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
hx8357_enter_standby(struct lcd_device * lcdev)275*4882a593Smuzhiyun static int hx8357_enter_standby(struct lcd_device *lcdev)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	int ret;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_OFF);
280*4882a593Smuzhiyun 	if (ret < 0)
281*4882a593Smuzhiyun 		return ret;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	usleep_range(10000, 12000);
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	ret = hx8357_spi_write_byte(lcdev, HX8357_ENTER_SLEEP_MODE);
286*4882a593Smuzhiyun 	if (ret < 0)
287*4882a593Smuzhiyun 		return ret;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	/*
290*4882a593Smuzhiyun 	 * The controller needs 120ms when entering in sleep mode before we can
291*4882a593Smuzhiyun 	 * send the command to go off sleep mode
292*4882a593Smuzhiyun 	 */
293*4882a593Smuzhiyun 	msleep(120);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	return 0;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
hx8357_exit_standby(struct lcd_device * lcdev)298*4882a593Smuzhiyun static int hx8357_exit_standby(struct lcd_device *lcdev)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	int ret;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
303*4882a593Smuzhiyun 	if (ret < 0)
304*4882a593Smuzhiyun 		return ret;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/*
307*4882a593Smuzhiyun 	 * The controller needs 120ms when exiting from sleep mode before we
308*4882a593Smuzhiyun 	 * can send the command to enter in sleep mode
309*4882a593Smuzhiyun 	 */
310*4882a593Smuzhiyun 	msleep(120);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
313*4882a593Smuzhiyun 	if (ret < 0)
314*4882a593Smuzhiyun 		return ret;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	return 0;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
hx8357_lcd_reset(struct lcd_device * lcdev)319*4882a593Smuzhiyun static void hx8357_lcd_reset(struct lcd_device *lcdev)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	struct hx8357_data *lcd = lcd_get_data(lcdev);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	/* Reset the screen */
324*4882a593Smuzhiyun 	gpio_set_value(lcd->reset, 1);
325*4882a593Smuzhiyun 	usleep_range(10000, 12000);
326*4882a593Smuzhiyun 	gpio_set_value(lcd->reset, 0);
327*4882a593Smuzhiyun 	usleep_range(10000, 12000);
328*4882a593Smuzhiyun 	gpio_set_value(lcd->reset, 1);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	/* The controller needs 120ms to recover from reset */
331*4882a593Smuzhiyun 	msleep(120);
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
hx8357_lcd_init(struct lcd_device * lcdev)334*4882a593Smuzhiyun static int hx8357_lcd_init(struct lcd_device *lcdev)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	struct hx8357_data *lcd = lcd_get_data(lcdev);
337*4882a593Smuzhiyun 	int ret;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	/*
340*4882a593Smuzhiyun 	 * Set the interface selection pins to SPI mode, with three
341*4882a593Smuzhiyun 	 * wires
342*4882a593Smuzhiyun 	 */
343*4882a593Smuzhiyun 	if (lcd->use_im_pins) {
344*4882a593Smuzhiyun 		gpio_set_value_cansleep(lcd->im_pins[0], 1);
345*4882a593Smuzhiyun 		gpio_set_value_cansleep(lcd->im_pins[1], 0);
346*4882a593Smuzhiyun 		gpio_set_value_cansleep(lcd->im_pins[2], 1);
347*4882a593Smuzhiyun 	}
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_power,
350*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_power));
351*4882a593Smuzhiyun 	if (ret < 0)
352*4882a593Smuzhiyun 		return ret;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_vcom,
355*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_vcom));
356*4882a593Smuzhiyun 	if (ret < 0)
357*4882a593Smuzhiyun 		return ret;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_power_normal,
360*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_power_normal));
361*4882a593Smuzhiyun 	if (ret < 0)
362*4882a593Smuzhiyun 		return ret;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_driving,
365*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_panel_driving));
366*4882a593Smuzhiyun 	if (ret < 0)
367*4882a593Smuzhiyun 		return ret;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_frame,
370*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_display_frame));
371*4882a593Smuzhiyun 	if (ret < 0)
372*4882a593Smuzhiyun 		return ret;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_related,
375*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_panel_related));
376*4882a593Smuzhiyun 	if (ret < 0)
377*4882a593Smuzhiyun 		return ret;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined1,
380*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_undefined1));
381*4882a593Smuzhiyun 	if (ret < 0)
382*4882a593Smuzhiyun 		return ret;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined2,
385*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_undefined2));
386*4882a593Smuzhiyun 	if (ret < 0)
387*4882a593Smuzhiyun 		return ret;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_gamma,
390*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_gamma));
391*4882a593Smuzhiyun 	if (ret < 0)
392*4882a593Smuzhiyun 		return ret;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_address_mode,
395*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_address_mode));
396*4882a593Smuzhiyun 	if (ret < 0)
397*4882a593Smuzhiyun 		return ret;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_pixel_format,
400*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_pixel_format));
401*4882a593Smuzhiyun 	if (ret < 0)
402*4882a593Smuzhiyun 		return ret;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_column_address,
405*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_column_address));
406*4882a593Smuzhiyun 	if (ret < 0)
407*4882a593Smuzhiyun 		return ret;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_page_address,
410*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_page_address));
411*4882a593Smuzhiyun 	if (ret < 0)
412*4882a593Smuzhiyun 		return ret;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_rgb,
415*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_rgb));
416*4882a593Smuzhiyun 	if (ret < 0)
417*4882a593Smuzhiyun 		return ret;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_mode,
420*4882a593Smuzhiyun 				ARRAY_SIZE(hx8357_seq_display_mode));
421*4882a593Smuzhiyun 	if (ret < 0)
422*4882a593Smuzhiyun 		return ret;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
425*4882a593Smuzhiyun 	if (ret < 0)
426*4882a593Smuzhiyun 		return ret;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	/*
429*4882a593Smuzhiyun 	 * The controller needs 120ms to fully recover from exiting sleep mode
430*4882a593Smuzhiyun 	 */
431*4882a593Smuzhiyun 	msleep(120);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
434*4882a593Smuzhiyun 	if (ret < 0)
435*4882a593Smuzhiyun 		return ret;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	usleep_range(5000, 7000);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	ret = hx8357_spi_write_byte(lcdev, HX8357_WRITE_MEMORY_START);
440*4882a593Smuzhiyun 	if (ret < 0)
441*4882a593Smuzhiyun 		return ret;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	return 0;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun 
hx8369_lcd_init(struct lcd_device * lcdev)446*4882a593Smuzhiyun static int hx8369_lcd_init(struct lcd_device *lcdev)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun 	int ret;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_extension_command,
451*4882a593Smuzhiyun 				ARRAY_SIZE(hx8369_seq_extension_command));
452*4882a593Smuzhiyun 	if (ret < 0)
453*4882a593Smuzhiyun 		return ret;
454*4882a593Smuzhiyun 	usleep_range(10000, 12000);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_display_related,
457*4882a593Smuzhiyun 				ARRAY_SIZE(hx8369_seq_display_related));
458*4882a593Smuzhiyun 	if (ret < 0)
459*4882a593Smuzhiyun 		return ret;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_panel_waveform_cycle,
462*4882a593Smuzhiyun 				ARRAY_SIZE(hx8369_seq_panel_waveform_cycle));
463*4882a593Smuzhiyun 	if (ret < 0)
464*4882a593Smuzhiyun 		return ret;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_address_mode,
467*4882a593Smuzhiyun 				ARRAY_SIZE(hx8369_seq_set_address_mode));
468*4882a593Smuzhiyun 	if (ret < 0)
469*4882a593Smuzhiyun 		return ret;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_vcom,
472*4882a593Smuzhiyun 				ARRAY_SIZE(hx8369_seq_vcom));
473*4882a593Smuzhiyun 	if (ret < 0)
474*4882a593Smuzhiyun 		return ret;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_gip,
477*4882a593Smuzhiyun 				ARRAY_SIZE(hx8369_seq_gip));
478*4882a593Smuzhiyun 	if (ret < 0)
479*4882a593Smuzhiyun 		return ret;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_power,
482*4882a593Smuzhiyun 				ARRAY_SIZE(hx8369_seq_power));
483*4882a593Smuzhiyun 	if (ret < 0)
484*4882a593Smuzhiyun 		return ret;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
487*4882a593Smuzhiyun 	if (ret < 0)
488*4882a593Smuzhiyun 		return ret;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	/*
491*4882a593Smuzhiyun 	 * The controller needs 120ms to fully recover from exiting sleep mode
492*4882a593Smuzhiyun 	 */
493*4882a593Smuzhiyun 	msleep(120);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_gamma_curve_related,
496*4882a593Smuzhiyun 				ARRAY_SIZE(hx8369_seq_gamma_curve_related));
497*4882a593Smuzhiyun 	if (ret < 0)
498*4882a593Smuzhiyun 		return ret;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
501*4882a593Smuzhiyun 	if (ret < 0)
502*4882a593Smuzhiyun 		return ret;
503*4882a593Smuzhiyun 	usleep_range(1000, 1200);
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_write_CABC_control,
506*4882a593Smuzhiyun 				ARRAY_SIZE(hx8369_seq_write_CABC_control));
507*4882a593Smuzhiyun 	if (ret < 0)
508*4882a593Smuzhiyun 		return ret;
509*4882a593Smuzhiyun 	usleep_range(10000, 12000);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev,
512*4882a593Smuzhiyun 			hx8369_seq_write_CABC_control_setting,
513*4882a593Smuzhiyun 			ARRAY_SIZE(hx8369_seq_write_CABC_control_setting));
514*4882a593Smuzhiyun 	if (ret < 0)
515*4882a593Smuzhiyun 		return ret;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev,
518*4882a593Smuzhiyun 			hx8369_seq_write_CABC_min_brightness,
519*4882a593Smuzhiyun 			ARRAY_SIZE(hx8369_seq_write_CABC_min_brightness));
520*4882a593Smuzhiyun 	if (ret < 0)
521*4882a593Smuzhiyun 		return ret;
522*4882a593Smuzhiyun 	usleep_range(10000, 12000);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_display_brightness,
525*4882a593Smuzhiyun 				ARRAY_SIZE(hx8369_seq_set_display_brightness));
526*4882a593Smuzhiyun 	if (ret < 0)
527*4882a593Smuzhiyun 		return ret;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
530*4882a593Smuzhiyun 	if (ret < 0)
531*4882a593Smuzhiyun 		return ret;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	return 0;
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun #define POWER_IS_ON(pwr)	((pwr) <= FB_BLANK_NORMAL)
537*4882a593Smuzhiyun 
hx8357_set_power(struct lcd_device * lcdev,int power)538*4882a593Smuzhiyun static int hx8357_set_power(struct lcd_device *lcdev, int power)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	struct hx8357_data *lcd = lcd_get_data(lcdev);
541*4882a593Smuzhiyun 	int ret = 0;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->state))
544*4882a593Smuzhiyun 		ret = hx8357_exit_standby(lcdev);
545*4882a593Smuzhiyun 	else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->state))
546*4882a593Smuzhiyun 		ret = hx8357_enter_standby(lcdev);
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	if (ret == 0)
549*4882a593Smuzhiyun 		lcd->state = power;
550*4882a593Smuzhiyun 	else
551*4882a593Smuzhiyun 		dev_warn(&lcdev->dev, "failed to set power mode %d\n", power);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	return ret;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun 
hx8357_get_power(struct lcd_device * lcdev)556*4882a593Smuzhiyun static int hx8357_get_power(struct lcd_device *lcdev)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	struct hx8357_data *lcd = lcd_get_data(lcdev);
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	return lcd->state;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun static struct lcd_ops hx8357_ops = {
564*4882a593Smuzhiyun 	.set_power	= hx8357_set_power,
565*4882a593Smuzhiyun 	.get_power	= hx8357_get_power,
566*4882a593Smuzhiyun };
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun static const struct of_device_id hx8357_dt_ids[] = {
569*4882a593Smuzhiyun 	{
570*4882a593Smuzhiyun 		.compatible = "himax,hx8357",
571*4882a593Smuzhiyun 		.data = hx8357_lcd_init,
572*4882a593Smuzhiyun 	},
573*4882a593Smuzhiyun 	{
574*4882a593Smuzhiyun 		.compatible = "himax,hx8369",
575*4882a593Smuzhiyun 		.data = hx8369_lcd_init,
576*4882a593Smuzhiyun 	},
577*4882a593Smuzhiyun 	{},
578*4882a593Smuzhiyun };
579*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
580*4882a593Smuzhiyun 
hx8357_probe(struct spi_device * spi)581*4882a593Smuzhiyun static int hx8357_probe(struct spi_device *spi)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun 	struct lcd_device *lcdev;
584*4882a593Smuzhiyun 	struct hx8357_data *lcd;
585*4882a593Smuzhiyun 	const struct of_device_id *match;
586*4882a593Smuzhiyun 	int i, ret;
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
589*4882a593Smuzhiyun 	if (!lcd)
590*4882a593Smuzhiyun 		return -ENOMEM;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	ret = spi_setup(spi);
593*4882a593Smuzhiyun 	if (ret < 0) {
594*4882a593Smuzhiyun 		dev_err(&spi->dev, "SPI setup failed.\n");
595*4882a593Smuzhiyun 		return ret;
596*4882a593Smuzhiyun 	}
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	lcd->spi = spi;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	match = of_match_device(hx8357_dt_ids, &spi->dev);
601*4882a593Smuzhiyun 	if (!match || !match->data)
602*4882a593Smuzhiyun 		return -EINVAL;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	lcd->reset = of_get_named_gpio(spi->dev.of_node, "gpios-reset", 0);
605*4882a593Smuzhiyun 	if (!gpio_is_valid(lcd->reset)) {
606*4882a593Smuzhiyun 		dev_err(&spi->dev, "Missing dt property: gpios-reset\n");
607*4882a593Smuzhiyun 		return -EINVAL;
608*4882a593Smuzhiyun 	}
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	ret = devm_gpio_request_one(&spi->dev, lcd->reset,
611*4882a593Smuzhiyun 				    GPIOF_OUT_INIT_HIGH,
612*4882a593Smuzhiyun 				    "hx8357-reset");
613*4882a593Smuzhiyun 	if (ret) {
614*4882a593Smuzhiyun 		dev_err(&spi->dev,
615*4882a593Smuzhiyun 			"failed to request gpio %d: %d\n",
616*4882a593Smuzhiyun 			lcd->reset, ret);
617*4882a593Smuzhiyun 		return -EINVAL;
618*4882a593Smuzhiyun 	}
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	if (of_find_property(spi->dev.of_node, "im-gpios", NULL)) {
621*4882a593Smuzhiyun 		lcd->use_im_pins = 1;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 		for (i = 0; i < HX8357_NUM_IM_PINS; i++) {
624*4882a593Smuzhiyun 			lcd->im_pins[i] = of_get_named_gpio(spi->dev.of_node,
625*4882a593Smuzhiyun 							    "im-gpios", i);
626*4882a593Smuzhiyun 			if (lcd->im_pins[i] == -EPROBE_DEFER) {
627*4882a593Smuzhiyun 				dev_info(&spi->dev, "GPIO requested is not here yet, deferring the probe\n");
628*4882a593Smuzhiyun 				return -EPROBE_DEFER;
629*4882a593Smuzhiyun 			}
630*4882a593Smuzhiyun 			if (!gpio_is_valid(lcd->im_pins[i])) {
631*4882a593Smuzhiyun 				dev_err(&spi->dev, "Missing dt property: im-gpios\n");
632*4882a593Smuzhiyun 				return -EINVAL;
633*4882a593Smuzhiyun 			}
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 			ret = devm_gpio_request_one(&spi->dev, lcd->im_pins[i],
636*4882a593Smuzhiyun 						    GPIOF_OUT_INIT_LOW,
637*4882a593Smuzhiyun 						    "im_pins");
638*4882a593Smuzhiyun 			if (ret) {
639*4882a593Smuzhiyun 				dev_err(&spi->dev, "failed to request gpio %d: %d\n",
640*4882a593Smuzhiyun 					lcd->im_pins[i], ret);
641*4882a593Smuzhiyun 				return -EINVAL;
642*4882a593Smuzhiyun 			}
643*4882a593Smuzhiyun 		}
644*4882a593Smuzhiyun 	} else {
645*4882a593Smuzhiyun 		lcd->use_im_pins = 0;
646*4882a593Smuzhiyun 	}
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd,
649*4882a593Smuzhiyun 					&hx8357_ops);
650*4882a593Smuzhiyun 	if (IS_ERR(lcdev)) {
651*4882a593Smuzhiyun 		ret = PTR_ERR(lcdev);
652*4882a593Smuzhiyun 		return ret;
653*4882a593Smuzhiyun 	}
654*4882a593Smuzhiyun 	spi_set_drvdata(spi, lcdev);
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	hx8357_lcd_reset(lcdev);
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	ret = ((int (*)(struct lcd_device *))match->data)(lcdev);
659*4882a593Smuzhiyun 	if (ret) {
660*4882a593Smuzhiyun 		dev_err(&spi->dev, "Couldn't initialize panel\n");
661*4882a593Smuzhiyun 		return ret;
662*4882a593Smuzhiyun 	}
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	dev_info(&spi->dev, "Panel probed\n");
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	return 0;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun static struct spi_driver hx8357_driver = {
670*4882a593Smuzhiyun 	.probe  = hx8357_probe,
671*4882a593Smuzhiyun 	.driver = {
672*4882a593Smuzhiyun 		.name = "hx8357",
673*4882a593Smuzhiyun 		.of_match_table = hx8357_dt_ids,
674*4882a593Smuzhiyun 	},
675*4882a593Smuzhiyun };
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun module_spi_driver(hx8357_driver);
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
680*4882a593Smuzhiyun MODULE_DESCRIPTION("Himax HX-8357 LCD Driver");
681*4882a593Smuzhiyun MODULE_LICENSE("GPL");
682