1 #include <linux/amba/bus.h>
2 #include <linux/amba/clcd.h>
3 #include <linux/gpio/consumer.h>
4 #include <linux/of.h>
5 #include <linux/of_graph.h>
6 #include <linux/delay.h>
7 #include <linux/bitops.h>
8 #include <linux/mfd/syscon.h>
9 #include <linux/regmap.h>
10 
11 #include "amba-clcd-nomadik.h"
12 
13 static struct gpio_desc *grestb;
14 static struct gpio_desc *scen;
15 static struct gpio_desc *scl;
16 static struct gpio_desc *sda;
17 
tpg110_readwrite_reg(bool write,u8 address,u8 outval)18 static u8 tpg110_readwrite_reg(bool write, u8 address, u8 outval)
19 {
20 	int i;
21 	u8 inval = 0;
22 
23 	/* Assert SCEN */
24 	gpiod_set_value_cansleep(scen, 1);
25 	ndelay(150);
26 	/* Hammer out the address */
27 	for (i = 5; i >= 0; i--) {
28 		if (address & BIT(i))
29 			gpiod_set_value_cansleep(sda, 1);
30 		else
31 			gpiod_set_value_cansleep(sda, 0);
32 		ndelay(150);
33 		/* Send an SCL pulse */
34 		gpiod_set_value_cansleep(scl, 1);
35 		ndelay(160);
36 		gpiod_set_value_cansleep(scl, 0);
37 		ndelay(160);
38 	}
39 
40 	if (write) {
41 		/* WRITE */
42 		gpiod_set_value_cansleep(sda, 0);
43 	} else {
44 		/* READ */
45 		gpiod_set_value_cansleep(sda, 1);
46 	}
47 	ndelay(150);
48 	/* Send an SCL pulse */
49 	gpiod_set_value_cansleep(scl, 1);
50 	ndelay(160);
51 	gpiod_set_value_cansleep(scl, 0);
52 	ndelay(160);
53 
54 	if (!write)
55 		/* HiZ turn-around cycle */
56 		gpiod_direction_input(sda);
57 	ndelay(150);
58 	/* Send an SCL pulse */
59 	gpiod_set_value_cansleep(scl, 1);
60 	ndelay(160);
61 	gpiod_set_value_cansleep(scl, 0);
62 	ndelay(160);
63 
64 	/* Hammer in/out the data */
65 	for (i = 7; i >= 0; i--) {
66 		int value;
67 
68 		if (write) {
69 			value = !!(outval & BIT(i));
70 			gpiod_set_value_cansleep(sda, value);
71 		} else {
72 			value = gpiod_get_value(sda);
73 			if (value)
74 				inval |= BIT(i);
75 		}
76 		ndelay(150);
77 		/* Send an SCL pulse */
78 		gpiod_set_value_cansleep(scl, 1);
79 		ndelay(160);
80 		gpiod_set_value_cansleep(scl, 0);
81 		ndelay(160);
82 	}
83 
84 	gpiod_direction_output(sda, 0);
85 	/* Deassert SCEN */
86 	gpiod_set_value_cansleep(scen, 0);
87 	/* Satisfies SCEN pulse width */
88 	udelay(1);
89 
90 	return inval;
91 }
92 
tpg110_read_reg(u8 address)93 static u8 tpg110_read_reg(u8 address)
94 {
95 	return tpg110_readwrite_reg(false, address, 0);
96 }
97 
tpg110_write_reg(u8 address,u8 outval)98 static void tpg110_write_reg(u8 address, u8 outval)
99 {
100 	tpg110_readwrite_reg(true, address, outval);
101 }
102 
tpg110_startup(struct device * dev)103 static void tpg110_startup(struct device *dev)
104 {
105 	u8 val;
106 
107 	dev_info(dev, "TPG110 display enable\n");
108 	/* De-assert the reset signal */
109 	gpiod_set_value_cansleep(grestb, 0);
110 	mdelay(1);
111 	dev_info(dev, "de-asserted GRESTB\n");
112 
113 	/* Test display communication */
114 	tpg110_write_reg(0x00, 0x55);
115 	val = tpg110_read_reg(0x00);
116 	if (val == 0x55)
117 		dev_info(dev, "passed communication test\n");
118 	val = tpg110_read_reg(0x01);
119 	dev_info(dev, "TPG110 chip ID: %d version: %d\n",
120 		val>>4, val&0x0f);
121 
122 	/* Show display resolution */
123 	val = tpg110_read_reg(0x02);
124 	val &= 7;
125 	switch (val) {
126 	case 0x0:
127 		dev_info(dev, "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)");
128 		break;
129 	case 0x1:
130 		dev_info(dev, "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)");
131 		break;
132 	case 0x4:
133 		dev_info(dev, "480x640 RGB");
134 		break;
135 	case 0x5:
136 		dev_info(dev, "480x272 RGB");
137 		break;
138 	case 0x6:
139 		dev_info(dev, "640x480 RGB");
140 		break;
141 	case 0x7:
142 		dev_info(dev, "800x480 RGB");
143 		break;
144 	default:
145 		dev_info(dev, "ILLEGAL RESOLUTION");
146 		break;
147 	}
148 
149 	val = tpg110_read_reg(0x03);
150 	dev_info(dev, "resolution is controlled by %s\n",
151 		(val & BIT(7)) ? "software" : "hardware");
152 }
153 
tpg110_enable(struct clcd_fb * fb)154 static void tpg110_enable(struct clcd_fb *fb)
155 {
156 	struct device *dev = &fb->dev->dev;
157 	static bool startup;
158 	u8 val;
159 
160 	if (!startup) {
161 		tpg110_startup(dev);
162 		startup = true;
163 	}
164 
165 	/* Take chip out of standby */
166 	val = tpg110_read_reg(0x03);
167 	val |= BIT(0);
168 	tpg110_write_reg(0x03, val);
169 }
170 
tpg110_disable(struct clcd_fb * fb)171 static void tpg110_disable(struct clcd_fb *fb)
172 {
173 	u8 val;
174 
175 	dev_info(&fb->dev->dev, "TPG110 display disable\n");
176 	val = tpg110_read_reg(0x03);
177 	/* Put into standby */
178 	val &= ~BIT(0);
179 	tpg110_write_reg(0x03, val);
180 }
181 
tpg110_init(struct device * dev,struct device_node * np,struct clcd_board * board)182 static void tpg110_init(struct device *dev, struct device_node *np,
183 			struct clcd_board *board)
184 {
185 	dev_info(dev, "TPG110 display init\n");
186 
187 	/* This asserts the GRESTB signal, putting the display into reset */
188 	grestb = devm_fwnode_get_gpiod_from_child(dev, "grestb", &np->fwnode,
189 						  GPIOD_OUT_HIGH, "grestb");
190 	if (IS_ERR(grestb)) {
191 		dev_err(dev, "no GRESTB GPIO\n");
192 		return;
193 	}
194 	scen = devm_fwnode_get_gpiod_from_child(dev, "scen", &np->fwnode,
195 						GPIOD_OUT_LOW, "scen");
196 	if (IS_ERR(scen)) {
197 		dev_err(dev, "no SCEN GPIO\n");
198 		return;
199 	}
200 	scl = devm_fwnode_get_gpiod_from_child(dev, "scl", &np->fwnode,
201 					       GPIOD_OUT_LOW, "scl");
202 	if (IS_ERR(scl)) {
203 		dev_err(dev, "no SCL GPIO\n");
204 		return;
205 	}
206 	sda = devm_fwnode_get_gpiod_from_child(dev, "sda", &np->fwnode,
207 					       GPIOD_OUT_LOW, "sda");
208 	if (IS_ERR(sda)) {
209 		dev_err(dev, "no SDA GPIO\n");
210 		return;
211 	}
212 	board->enable = tpg110_enable;
213 	board->disable = tpg110_disable;
214 }
215 
nomadik_clcd_init_panel(struct clcd_fb * fb,struct device_node * panel)216 int nomadik_clcd_init_panel(struct clcd_fb *fb, struct device_node *panel)
217 {
218 	if (of_device_is_compatible(panel, "tpo,tpg110"))
219 		tpg110_init(&fb->dev->dev, panel, fb->board);
220 	else
221 		dev_info(&fb->dev->dev, "unknown panel\n");
222 
223 	/* Unknown panel, fall through */
224 	return 0;
225 }
226 EXPORT_SYMBOL_GPL(nomadik_clcd_init_panel);
227 
228 #define PMU_CTRL_OFFSET 0x0000
229 #define PMU_CTRL_LCDNDIF BIT(26)
230 
nomadik_clcd_init_board(struct amba_device * adev,struct clcd_board * board)231 int nomadik_clcd_init_board(struct amba_device *adev,
232 			    struct clcd_board *board)
233 {
234 	struct regmap *pmu_regmap;
235 
236 	dev_info(&adev->dev, "Nomadik CLCD board init\n");
237 	pmu_regmap =
238 		syscon_regmap_lookup_by_compatible("stericsson,nomadik-pmu");
239 	if (IS_ERR(pmu_regmap)) {
240 		dev_err(&adev->dev, "could not find PMU syscon regmap\n");
241 		return PTR_ERR(pmu_regmap);
242 	}
243 	regmap_update_bits(pmu_regmap,
244 			   PMU_CTRL_OFFSET,
245 			   PMU_CTRL_LCDNDIF,
246 			   0);
247 	dev_info(&adev->dev, "set PMU mux to CLCD mode\n");
248 
249 	return 0;
250 }
251 EXPORT_SYMBOL_GPL(nomadik_clcd_init_board);
252