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#include "dvo.h"
30
31#define CH7xxx_REG_VID 0x4a
32#define CH7xxx_REG_DID 0x4b
33
34#define CH7011_VID 0x83
35#define CH7010B_VID 0x05
36#define CH7009A_VID 0x84
37#define CH7009B_VID 0x85
38#define CH7301_VID 0x95
39
40#define CH7xxx_VID 0x84
41#define CH7xxx_DID 0x17
42#define CH7010_DID 0x16
43
44#define CH7xxx_NUM_REGS 0x4c
45
46#define CH7xxx_CM 0x1c
47#define CH7xxx_CM_XCM (1<<0)
48#define CH7xxx_CM_MCP (1<<2)
49#define CH7xxx_INPUT_CLOCK 0x1d
50#define CH7xxx_GPIO 0x1e
51#define CH7xxx_GPIO_HPIR (1<<3)
52#define CH7xxx_IDF 0x1f
53
54#define CH7xxx_IDF_HSP (1<<3)
55#define CH7xxx_IDF_VSP (1<<4)
56
57#define CH7xxx_CONNECTION_DETECT 0x20
58#define CH7xxx_CDET_DVI (1<<5)
59
60#define CH7301_DAC_CNTL 0x21
61#define CH7301_HOTPLUG 0x23
62#define CH7xxx_TCTL 0x31
63#define CH7xxx_TVCO 0x32
64#define CH7xxx_TPCP 0x33
65#define CH7xxx_TPD 0x34
66#define CH7xxx_TPVT 0x35
67#define CH7xxx_TLPF 0x36
68#define CH7xxx_TCT 0x37
69#define CH7301_TEST_PATTERN 0x48
70
71#define CH7xxx_PM 0x49
72#define CH7xxx_PM_FPD (1<<0)
73#define CH7301_PM_DACPD0 (1<<1)
74#define CH7301_PM_DACPD1 (1<<2)
75#define CH7301_PM_DACPD2 (1<<3)
76#define CH7xxx_PM_DVIL (1<<6)
77#define CH7xxx_PM_DVIP (1<<7)
78
79#define CH7301_SYNC_POLARITY 0x56
80#define CH7301_SYNC_RGB_YUV (1<<0)
81#define CH7301_SYNC_POL_DVI (1<<5)
82
83
84
85
86
87static struct ch7xxx_id_struct {
88 uint8_t vid;
89 char *name;
90} ch7xxx_ids[] = {
91 { CH7011_VID, "CH7011" },
92 { CH7010B_VID, "CH7010B" },
93 { CH7009A_VID, "CH7009A" },
94 { CH7009B_VID, "CH7009B" },
95 { CH7301_VID, "CH7301" },
96};
97
98static struct ch7xxx_did_struct {
99 uint8_t did;
100 char *name;
101} ch7xxx_dids[] = {
102 { CH7xxx_DID, "CH7XXX" },
103 { CH7010_DID, "CH7010B" },
104};
105
106struct ch7xxx_priv {
107 bool quiet;
108};
109
110static char *ch7xxx_get_id(uint8_t vid)
111{
112 int i;
113
114 for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
115 if (ch7xxx_ids[i].vid == vid)
116 return ch7xxx_ids[i].name;
117 }
118
119 return NULL;
120}
121
122static char *ch7xxx_get_did(uint8_t did)
123{
124 int i;
125
126 for (i = 0; i < ARRAY_SIZE(ch7xxx_dids); i++) {
127 if (ch7xxx_dids[i].did == did)
128 return ch7xxx_dids[i].name;
129 }
130
131 return NULL;
132}
133
134
135static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
136{
137 struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
138 struct i2c_adapter *adapter = dvo->i2c_bus;
139 u8 out_buf[2];
140 u8 in_buf[2];
141
142 struct i2c_msg msgs[] = {
143 {
144 .addr = dvo->slave_addr,
145 .flags = 0,
146 .len = 1,
147 .buf = out_buf,
148 },
149 {
150 .addr = dvo->slave_addr,
151 .flags = I2C_M_RD,
152 .len = 1,
153 .buf = in_buf,
154 }
155 };
156
157 out_buf[0] = addr;
158 out_buf[1] = 0;
159
160 if (i2c_transfer(adapter, msgs, 2) == 2) {
161 *ch = in_buf[0];
162 return true;
163 }
164
165 if (!ch7xxx->quiet) {
166 DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
167 addr, adapter->name, dvo->slave_addr);
168 }
169 return false;
170}
171
172
173static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
174{
175 struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
176 struct i2c_adapter *adapter = dvo->i2c_bus;
177 uint8_t out_buf[2];
178 struct i2c_msg msg = {
179 .addr = dvo->slave_addr,
180 .flags = 0,
181 .len = 2,
182 .buf = out_buf,
183 };
184
185 out_buf[0] = addr;
186 out_buf[1] = ch;
187
188 if (i2c_transfer(adapter, &msg, 1) == 1)
189 return true;
190
191 if (!ch7xxx->quiet) {
192 DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
193 addr, adapter->name, dvo->slave_addr);
194 }
195
196 return false;
197}
198
199static bool ch7xxx_init(struct intel_dvo_device *dvo,
200 struct i2c_adapter *adapter)
201{
202
203 struct ch7xxx_priv *ch7xxx;
204 uint8_t vendor, device;
205 char *name, *devid;
206
207 ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
208 if (ch7xxx == NULL)
209 return false;
210
211 dvo->i2c_bus = adapter;
212 dvo->dev_priv = ch7xxx;
213 ch7xxx->quiet = true;
214
215 if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
216 goto out;
217
218 name = ch7xxx_get_id(vendor);
219 if (!name) {
220 DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
221 "slave %d.\n",
222 vendor, adapter->name, dvo->slave_addr);
223 goto out;
224 }
225
226
227 if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
228 goto out;
229
230 devid = ch7xxx_get_did(device);
231 if (!devid) {
232 DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
233 "slave %d.\n",
234 vendor, adapter->name, dvo->slave_addr);
235 goto out;
236 }
237
238 ch7xxx->quiet = false;
239 DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
240 name, vendor, device);
241 return true;
242out:
243 kfree(ch7xxx);
244 return false;
245}
246
247static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
248{
249 uint8_t cdet, orig_pm, pm;
250
251 ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
252
253 pm = orig_pm;
254 pm &= ~CH7xxx_PM_FPD;
255 pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
256
257 ch7xxx_writeb(dvo, CH7xxx_PM, pm);
258
259 ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
260
261 ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
262
263 if (cdet & CH7xxx_CDET_DVI)
264 return connector_status_connected;
265 return connector_status_disconnected;
266}
267
268static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
269 struct drm_display_mode *mode)
270{
271 if (mode->clock > 165000)
272 return MODE_CLOCK_HIGH;
273
274 return MODE_OK;
275}
276
277static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
278 const struct drm_display_mode *mode,
279 const struct drm_display_mode *adjusted_mode)
280{
281 uint8_t tvco, tpcp, tpd, tlpf, idf;
282
283 if (mode->clock <= 65000) {
284 tvco = 0x23;
285 tpcp = 0x08;
286 tpd = 0x16;
287 tlpf = 0x60;
288 } else {
289 tvco = 0x2d;
290 tpcp = 0x06;
291 tpd = 0x26;
292 tlpf = 0xa0;
293 }
294
295 ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
296 ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
297 ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
298 ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
299 ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
300 ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
301 ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
302
303 ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
304
305 idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
306 if (mode->flags & DRM_MODE_FLAG_PHSYNC)
307 idf |= CH7xxx_IDF_HSP;
308
309 if (mode->flags & DRM_MODE_FLAG_PVSYNC)
310 idf |= CH7xxx_IDF_VSP;
311
312 ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
313}
314
315
316static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
317{
318 if (enable)
319 ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
320 else
321 ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
322}
323
324static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
325{
326 u8 val;
327
328 ch7xxx_readb(dvo, CH7xxx_PM, &val);
329
330 if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
331 return true;
332 else
333 return false;
334}
335
336static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
337{
338 int i;
339
340 for (i = 0; i < CH7xxx_NUM_REGS; i++) {
341 uint8_t val;
342 if ((i % 8) == 0)
343 DRM_DEBUG_KMS("\n %02X: ", i);
344 ch7xxx_readb(dvo, i, &val);
345 DRM_DEBUG_KMS("%02X ", val);
346 }
347}
348
349static void ch7xxx_destroy(struct intel_dvo_device *dvo)
350{
351 struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
352
353 if (ch7xxx) {
354 kfree(ch7xxx);
355 dvo->dev_priv = NULL;
356 }
357}
358
359const struct intel_dvo_dev_ops ch7xxx_ops = {
360 .init = ch7xxx_init,
361 .detect = ch7xxx_detect,
362 .mode_valid = ch7xxx_mode_valid,
363 .mode_set = ch7xxx_mode_set,
364 .dpms = ch7xxx_dpms,
365 .get_hw_state = ch7xxx_get_hw_state,
366 .dump_regs = ch7xxx_dump_regs,
367 .destroy = ch7xxx_destroy,
368};
369