summaryrefslogtreecommitdiff
path: root/drivers/video/hx8238d.c
blob: 6ee97cb4ff3a8ae344fae7ca766284ea384a865f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copied from simple-panel
 * Copyright (c) 2016 Google, Inc
 * Written by Simon Glass <sjg@chromium.org>
 * Copyright (c) 2018 Sjoerd Simons <sjoerd.simons@collabora.co.uk>
 * Modified by Moses Christopher <BollavarapuMoses.Christopher@in.bosch.com>
 *
 * Panel Initialization for HX8238D panel from Himax
 * Resolution: 320x240
 * Color-Mode: RGB
 *
 */

#include <common.h>
#include <dm.h>
#include <panel.h>
#include <spi.h>

DECLARE_GLOBAL_DATA_PTR;

/* Register Address */
#define HX8238D_OUTPUT_CTRL_ADDR        0x01
#define HX8238D_LCD_AC_CTRL_ADDR        0x02
#define HX8238D_POWER_CTRL_1_ADDR       0x03
#define HX8238D_DATA_CLR_CTRL_ADDR      0X04
#define HX8238D_FUNCTION_CTRL_ADDR      0x05
#define HX8238D_LED_CTRL_ADDR           0x08
#define HX8238D_CONT_BRIGHT_CTRL_ADDR   0x0A
#define HX8238D_FRAME_CYCLE_CTRL_ADDR   0x0B
#define HX8238D_POWER_CTRL_2_ADDR       0x0D
#define HX8238D_POWER_CTRL_3_ADDR       0x0E
#define HX8238D_GATE_SCAN_POS_ADDR      0x0F
#define HX8238D_HORIZONTAL_PORCH_ADDR   0x16
#define HX8238D_VERTICAL_PORCH_ADDR     0x17
#define HX8238D_POWER_CTRL_4_ADDR       0x1E
#define HX8238D_GAMMA_CTRL_1_ADDR       0x30
#define HX8238D_GAMMA_CTRL_2_ADDR       0x31
#define HX8238D_GAMMA_CTRL_3_ADDR       0x32
#define HX8238D_GAMMA_CTRL_4_ADDR       0x33
#define HX8238D_GAMMA_CTRL_5_ADDR       0x34
#define HX8238D_GAMMA_CTRL_6_ADDR       0x35
#define HX8238D_GAMMA_CTRL_7_ADDR       0x36
#define HX8238D_GAMMA_CTRL_8_ADDR       0x37
#define HX8238D_GAMMA_CTRL_9_ADDR       0x3A
#define HX8238D_GAMMA_CTRL_10_ADDR      0x3B

/* Register Data */
#define HX8238D_OUTPUT_CTRL             0x6300
#define HX8238D_LCD_AC_CTRL             0x0200
#define HX8238D_POWER_CTRL_1            0x6564
#define HX8238D_DATA_CLR_CTRL           0x04C7
#define HX8238D_FUNCTION_CTRL           0xA884
#define HX8238D_LED_CTRL                0x00CE
#define HX8238D_CONT_BRIGHT_CTRL        0x4008
#define HX8238D_FRAME_CYCLE_CTRL        0xD400
#define HX8238D_POWER_CTRL_2            0x3229
#define HX8238D_POWER_CTRL_3            0x1200
#define HX8238D_GATE_SCAN_POS           0x0000
#define HX8238D_HORIZONTAL_PORCH        0x9F80
#define HX8238D_VERTICAL_PORCH          0x3F02
#define HX8238D_POWER_CTRL_4            0x005C

/* Gamma Control */
#define HX8238D_GAMMA_CTRL_1            0x0103
#define HX8238D_GAMMA_CTRL_2            0x0407
#define HX8238D_GAMMA_CTRL_3            0x0705
#define HX8238D_GAMMA_CTRL_4            0x0002
#define HX8238D_GAMMA_CTRL_5            0x0505
#define HX8238D_GAMMA_CTRL_6            0x0303
#define HX8238D_GAMMA_CTRL_7            0x0707
#define HX8238D_GAMMA_CTRL_8            0x0100
#define HX8238D_GAMMA_CTRL_9            0x1F00
#define HX8238D_GAMMA_CTRL_10           0x000F

/* Primary SPI register identification, 011100 */
/* Select register, RS=0, RS=0 */
/* Write  register, RS=1, RW=0 */
#define HX8238D_PRIMARY_SELECT_REG 0x70
#define HX8238D_PRIMARY_WRITE_REG  (HX8238D_PRIMARY_SELECT_REG | (0x1 << 1))

#define HX8238D_REG_BIT_LEN        24

struct hx8238d_priv {
	struct spi_slave *spi;
};

static int hx8238d_ofdata_to_platdata(struct udevice *dev)
{
	struct hx8238d_priv *priv = dev_get_priv(dev);

	priv->spi = dev_get_parent_priv(dev);

	return 0;
}

/* data[0] => REGISTER ADDRESS */
/* data[1] => REGISTER VALUE   */
struct hx8238d_command {
	u16 data[2];
};

static struct hx8238d_command hx8238d_init_commands[] = {
	{ .data = { HX8238D_OUTPUT_CTRL_ADDR,      HX8238D_OUTPUT_CTRL } },
	{ .data = { HX8238D_LCD_AC_CTRL_ADDR,      HX8238D_LCD_AC_CTRL } },
	{ .data = { HX8238D_POWER_CTRL_1_ADDR,     HX8238D_POWER_CTRL_1 } },
	{ .data = { HX8238D_DATA_CLR_CTRL_ADDR,    HX8238D_DATA_CLR_CTRL } },
	{ .data = { HX8238D_FUNCTION_CTRL_ADDR,    HX8238D_FUNCTION_CTRL } },
	{ .data = { HX8238D_LED_CTRL_ADDR,         HX8238D_LED_CTRL } },
	{ .data = { HX8238D_CONT_BRIGHT_CTRL_ADDR, HX8238D_CONT_BRIGHT_CTRL } },
	{ .data = { HX8238D_FRAME_CYCLE_CTRL_ADDR, HX8238D_FRAME_CYCLE_CTRL } },
	{ .data = { HX8238D_POWER_CTRL_2_ADDR,     HX8238D_POWER_CTRL_2 } },
	{ .data = { HX8238D_POWER_CTRL_3_ADDR,     HX8238D_POWER_CTRL_3 } },
	{ .data = { HX8238D_GATE_SCAN_POS_ADDR,    HX8238D_GATE_SCAN_POS } },
	{ .data = { HX8238D_HORIZONTAL_PORCH_ADDR, HX8238D_HORIZONTAL_PORCH } },
	{ .data = { HX8238D_VERTICAL_PORCH_ADDR,   HX8238D_VERTICAL_PORCH } },
	{ .data = { HX8238D_POWER_CTRL_4_ADDR,     HX8238D_POWER_CTRL_4 } },
	{ .data = { HX8238D_GAMMA_CTRL_1_ADDR,     HX8238D_GAMMA_CTRL_1 } },
	{ .data = { HX8238D_GAMMA_CTRL_2_ADDR,     HX8238D_GAMMA_CTRL_2 } },
	{ .data = { HX8238D_GAMMA_CTRL_3_ADDR,     HX8238D_GAMMA_CTRL_3 } },
	{ .data = { HX8238D_GAMMA_CTRL_4_ADDR,     HX8238D_GAMMA_CTRL_4 } },
	{ .data = { HX8238D_GAMMA_CTRL_5_ADDR,     HX8238D_GAMMA_CTRL_5 } },
	{ .data = { HX8238D_GAMMA_CTRL_6_ADDR,     HX8238D_GAMMA_CTRL_6 } },
	{ .data = { HX8238D_GAMMA_CTRL_7_ADDR,     HX8238D_GAMMA_CTRL_7 } },
	{ .data = { HX8238D_GAMMA_CTRL_8_ADDR,     HX8238D_GAMMA_CTRL_8 } },
	{ .data = { HX8238D_GAMMA_CTRL_9_ADDR,     HX8238D_GAMMA_CTRL_9 } },
	{ .data = { HX8238D_GAMMA_CTRL_10_ADDR,    HX8238D_GAMMA_CTRL_10 } },
};

/*
 * Generate Primary Register Buffer for Register Select and Register Write
 * First 6 MSB bits of Primary Register is represented with 011100
 *
 */
static void hx8238d_generate_reg_buffers(struct hx8238d_command command,
					 u8 *sr_buf, uint8_t *wr_buf)
{
	struct hx8238d_command cmd = command;

	sr_buf[0] = HX8238D_PRIMARY_SELECT_REG;
	sr_buf[1] = (cmd.data[0] >> 8) & 0xff;
	sr_buf[2] = (cmd.data[0]) & 0xff;

	wr_buf[0] = HX8238D_PRIMARY_WRITE_REG;
	wr_buf[1] = (cmd.data[1] >> 8) & 0xff;
	wr_buf[2] = (cmd.data[1]) & 0xff;
}

static int hx8238d_probe(struct udevice *dev)
{
	struct hx8238d_priv *priv = dev_get_priv(dev);
	int ret;

	ret = spi_claim_bus(priv->spi);
	if (ret) {
		debug("Failed to claim bus: %d\n", ret);
		return ret;
	}

	for (int i = 0; i < ARRAY_SIZE(hx8238d_init_commands); i++) {
		u8 sr_buf[3], wr_buf[3];
		const struct hx8238d_command cmd = hx8238d_init_commands[i];

		hx8238d_generate_reg_buffers(cmd, sr_buf, wr_buf);
		ret = spi_xfer(priv->spi, HX8238D_REG_BIT_LEN, sr_buf, NULL,
			       SPI_XFER_BEGIN | SPI_XFER_END);
		if (ret) {
			debug("Failed to select register %d\n", ret);
			goto free;
		}

		ret = spi_xfer(priv->spi, HX8238D_REG_BIT_LEN, wr_buf, NULL,
			       SPI_XFER_BEGIN | SPI_XFER_END);
		if (ret) {
			debug("Failed to write value %d\n", ret);
			goto free;
		}
	}

free:
	spi_release_bus(priv->spi);
	return ret;
}

static const struct udevice_id hx8238d_ids[] = {
	{ .compatible = "himax,hx8238d" },
	{ }
};

U_BOOT_DRIVER(hx8238d) = {
	.name = "hx8238d",
	.id = UCLASS_PANEL,
	.of_match = hx8238d_ids,
	.of_to_plat = hx8238d_ofdata_to_platdata,
	.probe = hx8238d_probe,
	.priv_auto = sizeof(struct hx8238d_priv),
};