Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dvo_ch7xxx.c
Go to the documentation of this file.
1 /**************************************************************************
2 
3 Copyright © 2006 Dave Airlie
4 
5 All Rights Reserved.
6 
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sub license, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice (including the
16 next paragraph) shall be included in all copies or substantial portions
17 of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
23 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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 /* 7010 as well */
35 #define CH7009A_VID 0x84
36 #define CH7009B_VID 0x85
37 #define CH7301_VID 0x95
38 
39 #define CH7xxx_VID 0x84
40 #define CH7xxx_DID 0x17
41 
42 #define CH7xxx_NUM_REGS 0x4c
43 
44 #define CH7xxx_CM 0x1c
45 #define CH7xxx_CM_XCM (1<<0)
46 #define CH7xxx_CM_MCP (1<<2)
47 #define CH7xxx_INPUT_CLOCK 0x1d
48 #define CH7xxx_GPIO 0x1e
49 #define CH7xxx_GPIO_HPIR (1<<3)
50 #define CH7xxx_IDF 0x1f
51 
52 #define CH7xxx_IDF_HSP (1<<3)
53 #define CH7xxx_IDF_VSP (1<<4)
54 
55 #define CH7xxx_CONNECTION_DETECT 0x20
56 #define CH7xxx_CDET_DVI (1<<5)
57 
58 #define CH7301_DAC_CNTL 0x21
59 #define CH7301_HOTPLUG 0x23
60 #define CH7xxx_TCTL 0x31
61 #define CH7xxx_TVCO 0x32
62 #define CH7xxx_TPCP 0x33
63 #define CH7xxx_TPD 0x34
64 #define CH7xxx_TPVT 0x35
65 #define CH7xxx_TLPF 0x36
66 #define CH7xxx_TCT 0x37
67 #define CH7301_TEST_PATTERN 0x48
68 
69 #define CH7xxx_PM 0x49
70 #define CH7xxx_PM_FPD (1<<0)
71 #define CH7301_PM_DACPD0 (1<<1)
72 #define CH7301_PM_DACPD1 (1<<2)
73 #define CH7301_PM_DACPD2 (1<<3)
74 #define CH7xxx_PM_DVIL (1<<6)
75 #define CH7xxx_PM_DVIP (1<<7)
76 
77 #define CH7301_SYNC_POLARITY 0x56
78 #define CH7301_SYNC_RGB_YUV (1<<0)
79 #define CH7301_SYNC_POL_DVI (1<<5)
80 
85 static struct ch7xxx_id_struct {
86  uint8_t vid;
87  char *name;
88 } ch7xxx_ids[] = {
89  { CH7011_VID, "CH7011" },
90  { CH7009A_VID, "CH7009A" },
91  { CH7009B_VID, "CH7009B" },
92  { CH7301_VID, "CH7301" },
93 };
94 
95 struct ch7xxx_priv {
96  bool quiet;
97 };
98 
99 static char *ch7xxx_get_id(uint8_t vid)
100 {
101  int i;
102 
103  for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
104  if (ch7xxx_ids[i].vid == vid)
105  return ch7xxx_ids[i].name;
106  }
107 
108  return NULL;
109 }
110 
112 static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
113 {
114  struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
115  struct i2c_adapter *adapter = dvo->i2c_bus;
116  u8 out_buf[2];
117  u8 in_buf[2];
118 
119  struct i2c_msg msgs[] = {
120  {
121  .addr = dvo->slave_addr,
122  .flags = 0,
123  .len = 1,
124  .buf = out_buf,
125  },
126  {
127  .addr = dvo->slave_addr,
128  .flags = I2C_M_RD,
129  .len = 1,
130  .buf = in_buf,
131  }
132  };
133 
134  out_buf[0] = addr;
135  out_buf[1] = 0;
136 
137  if (i2c_transfer(adapter, msgs, 2) == 2) {
138  *ch = in_buf[0];
139  return true;
140  };
141 
142  if (!ch7xxx->quiet) {
143  DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
144  addr, adapter->name, dvo->slave_addr);
145  }
146  return false;
147 }
148 
150 static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
151 {
152  struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
153  struct i2c_adapter *adapter = dvo->i2c_bus;
154  uint8_t out_buf[2];
155  struct i2c_msg msg = {
156  .addr = dvo->slave_addr,
157  .flags = 0,
158  .len = 2,
159  .buf = out_buf,
160  };
161 
162  out_buf[0] = addr;
163  out_buf[1] = ch;
164 
165  if (i2c_transfer(adapter, &msg, 1) == 1)
166  return true;
167 
168  if (!ch7xxx->quiet) {
169  DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
170  addr, adapter->name, dvo->slave_addr);
171  }
172 
173  return false;
174 }
175 
176 static bool ch7xxx_init(struct intel_dvo_device *dvo,
177  struct i2c_adapter *adapter)
178 {
179  /* this will detect the CH7xxx chip on the specified i2c bus */
180  struct ch7xxx_priv *ch7xxx;
182  char *name;
183 
184  ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
185  if (ch7xxx == NULL)
186  return false;
187 
188  dvo->i2c_bus = adapter;
189  dvo->dev_priv = ch7xxx;
190  ch7xxx->quiet = true;
191 
192  if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
193  goto out;
194 
195  name = ch7xxx_get_id(vendor);
196  if (!name) {
197  DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
198  "slave %d.\n",
199  vendor, adapter->name, dvo->slave_addr);
200  goto out;
201  }
202 
203 
204  if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
205  goto out;
206 
207  if (device != CH7xxx_DID) {
208  DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
209  "slave %d.\n",
210  vendor, adapter->name, dvo->slave_addr);
211  goto out;
212  }
213 
214  ch7xxx->quiet = false;
215  DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
216  name, vendor, device);
217  return true;
218 out:
219  kfree(ch7xxx);
220  return false;
221 }
222 
223 static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
224 {
225  uint8_t cdet, orig_pm, pm;
226 
227  ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
228 
229  pm = orig_pm;
230  pm &= ~CH7xxx_PM_FPD;
232 
233  ch7xxx_writeb(dvo, CH7xxx_PM, pm);
234 
235  ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
236 
237  ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
238 
239  if (cdet & CH7xxx_CDET_DVI)
242 }
243 
244 static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
245  struct drm_display_mode *mode)
246 {
247  if (mode->clock > 165000)
248  return MODE_CLOCK_HIGH;
249 
250  return MODE_OK;
251 }
252 
253 static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
254  struct drm_display_mode *mode,
255  struct drm_display_mode *adjusted_mode)
256 {
257  uint8_t tvco, tpcp, tpd, tlpf, idf;
258 
259  if (mode->clock <= 65000) {
260  tvco = 0x23;
261  tpcp = 0x08;
262  tpd = 0x16;
263  tlpf = 0x60;
264  } else {
265  tvco = 0x2d;
266  tpcp = 0x06;
267  tpd = 0x26;
268  tlpf = 0xa0;
269  }
270 
271  ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
272  ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
273  ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
274  ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
275  ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
276  ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
277  ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
278 
279  ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
280 
281  idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
282  if (mode->flags & DRM_MODE_FLAG_PHSYNC)
283  idf |= CH7xxx_IDF_HSP;
284 
285  if (mode->flags & DRM_MODE_FLAG_PVSYNC)
286  idf |= CH7xxx_IDF_HSP;
287 
288  ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
289 }
290 
291 /* set the CH7xxx power state */
292 static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
293 {
294  if (enable)
295  ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
296  else
297  ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
298 }
299 
300 static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
301 {
302  u8 val;
303 
304  ch7xxx_readb(dvo, CH7xxx_PM, &val);
305 
306  if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
307  return true;
308  else
309  return false;
310 }
311 
312 static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
313 {
314  int i;
315 
316  for (i = 0; i < CH7xxx_NUM_REGS; i++) {
317  uint8_t val;
318  if ((i % 8) == 0)
319  DRM_LOG_KMS("\n %02X: ", i);
320  ch7xxx_readb(dvo, i, &val);
321  DRM_LOG_KMS("%02X ", val);
322  }
323 }
324 
325 static void ch7xxx_destroy(struct intel_dvo_device *dvo)
326 {
327  struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
328 
329  if (ch7xxx) {
330  kfree(ch7xxx);
331  dvo->dev_priv = NULL;
332  }
333 }
334 
336  .init = ch7xxx_init,
337  .detect = ch7xxx_detect,
338  .mode_valid = ch7xxx_mode_valid,
339  .mode_set = ch7xxx_mode_set,
340  .dpms = ch7xxx_dpms,
341  .get_hw_state = ch7xxx_get_hw_state,
342  .dump_regs = ch7xxx_dump_regs,
343  .destroy = ch7xxx_destroy,
344 };