1*4882a593Smuzhiyun /**************************************************************************
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun Copyright © 2006 Dave Airlie
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun All Rights Reserved.
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun Permission is hereby granted, free of charge, to any person obtaining a
8*4882a593Smuzhiyun copy of this software and associated documentation files (the
9*4882a593Smuzhiyun "Software"), to deal in the Software without restriction, including
10*4882a593Smuzhiyun without limitation the rights to use, copy, modify, merge, publish,
11*4882a593Smuzhiyun distribute, sub license, and/or sell copies of the Software, and to
12*4882a593Smuzhiyun permit persons to whom the Software is furnished to do so, subject to
13*4882a593Smuzhiyun the following conditions:
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun The above copyright notice and this permission notice (including the
16*4882a593Smuzhiyun next paragraph) shall be included in all copies or substantial portions
17*4882a593Smuzhiyun of the Software.
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20*4882a593Smuzhiyun OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21*4882a593Smuzhiyun MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22*4882a593Smuzhiyun IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
23*4882a593Smuzhiyun ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24*4882a593Smuzhiyun TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25*4882a593Smuzhiyun SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun **************************************************************************/
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #include "intel_display_types.h"
30*4882a593Smuzhiyun #include "intel_dvo_dev.h"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define SIL164_VID 0x0001
33*4882a593Smuzhiyun #define SIL164_DID 0x0006
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define SIL164_VID_LO 0x00
36*4882a593Smuzhiyun #define SIL164_VID_HI 0x01
37*4882a593Smuzhiyun #define SIL164_DID_LO 0x02
38*4882a593Smuzhiyun #define SIL164_DID_HI 0x03
39*4882a593Smuzhiyun #define SIL164_REV 0x04
40*4882a593Smuzhiyun #define SIL164_RSVD 0x05
41*4882a593Smuzhiyun #define SIL164_FREQ_LO 0x06
42*4882a593Smuzhiyun #define SIL164_FREQ_HI 0x07
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #define SIL164_REG8 0x08
45*4882a593Smuzhiyun #define SIL164_8_VEN (1<<5)
46*4882a593Smuzhiyun #define SIL164_8_HEN (1<<4)
47*4882a593Smuzhiyun #define SIL164_8_DSEL (1<<3)
48*4882a593Smuzhiyun #define SIL164_8_BSEL (1<<2)
49*4882a593Smuzhiyun #define SIL164_8_EDGE (1<<1)
50*4882a593Smuzhiyun #define SIL164_8_PD (1<<0)
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define SIL164_REG9 0x09
53*4882a593Smuzhiyun #define SIL164_9_VLOW (1<<7)
54*4882a593Smuzhiyun #define SIL164_9_MSEL_MASK (0x7<<4)
55*4882a593Smuzhiyun #define SIL164_9_TSEL (1<<3)
56*4882a593Smuzhiyun #define SIL164_9_RSEN (1<<2)
57*4882a593Smuzhiyun #define SIL164_9_HTPLG (1<<1)
58*4882a593Smuzhiyun #define SIL164_9_MDI (1<<0)
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun #define SIL164_REGC 0x0c
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun struct sil164_priv {
63*4882a593Smuzhiyun //I2CDevRec d;
64*4882a593Smuzhiyun bool quiet;
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun #define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
68*4882a593Smuzhiyun
sil164_readb(struct intel_dvo_device * dvo,int addr,u8 * ch)69*4882a593Smuzhiyun static bool sil164_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun struct sil164_priv *sil = dvo->dev_priv;
72*4882a593Smuzhiyun struct i2c_adapter *adapter = dvo->i2c_bus;
73*4882a593Smuzhiyun u8 out_buf[2];
74*4882a593Smuzhiyun u8 in_buf[2];
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun struct i2c_msg msgs[] = {
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun .addr = dvo->slave_addr,
79*4882a593Smuzhiyun .flags = 0,
80*4882a593Smuzhiyun .len = 1,
81*4882a593Smuzhiyun .buf = out_buf,
82*4882a593Smuzhiyun },
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun .addr = dvo->slave_addr,
85*4882a593Smuzhiyun .flags = I2C_M_RD,
86*4882a593Smuzhiyun .len = 1,
87*4882a593Smuzhiyun .buf = in_buf,
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun out_buf[0] = addr;
92*4882a593Smuzhiyun out_buf[1] = 0;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun if (i2c_transfer(adapter, msgs, 2) == 2) {
95*4882a593Smuzhiyun *ch = in_buf[0];
96*4882a593Smuzhiyun return true;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (!sil->quiet) {
100*4882a593Smuzhiyun DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
101*4882a593Smuzhiyun addr, adapter->name, dvo->slave_addr);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun return false;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
sil164_writeb(struct intel_dvo_device * dvo,int addr,u8 ch)106*4882a593Smuzhiyun static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun struct sil164_priv *sil = dvo->dev_priv;
109*4882a593Smuzhiyun struct i2c_adapter *adapter = dvo->i2c_bus;
110*4882a593Smuzhiyun u8 out_buf[2];
111*4882a593Smuzhiyun struct i2c_msg msg = {
112*4882a593Smuzhiyun .addr = dvo->slave_addr,
113*4882a593Smuzhiyun .flags = 0,
114*4882a593Smuzhiyun .len = 2,
115*4882a593Smuzhiyun .buf = out_buf,
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun out_buf[0] = addr;
119*4882a593Smuzhiyun out_buf[1] = ch;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun if (i2c_transfer(adapter, &msg, 1) == 1)
122*4882a593Smuzhiyun return true;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (!sil->quiet) {
125*4882a593Smuzhiyun DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
126*4882a593Smuzhiyun addr, adapter->name, dvo->slave_addr);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun return false;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /* Silicon Image 164 driver for chip on i2c bus */
sil164_init(struct intel_dvo_device * dvo,struct i2c_adapter * adapter)133*4882a593Smuzhiyun static bool sil164_init(struct intel_dvo_device *dvo,
134*4882a593Smuzhiyun struct i2c_adapter *adapter)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun /* this will detect the SIL164 chip on the specified i2c bus */
137*4882a593Smuzhiyun struct sil164_priv *sil;
138*4882a593Smuzhiyun unsigned char ch;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL);
141*4882a593Smuzhiyun if (sil == NULL)
142*4882a593Smuzhiyun return false;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun dvo->i2c_bus = adapter;
145*4882a593Smuzhiyun dvo->dev_priv = sil;
146*4882a593Smuzhiyun sil->quiet = true;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (!sil164_readb(dvo, SIL164_VID_LO, &ch))
149*4882a593Smuzhiyun goto out;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun if (ch != (SIL164_VID & 0xff)) {
152*4882a593Smuzhiyun DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
153*4882a593Smuzhiyun ch, adapter->name, dvo->slave_addr);
154*4882a593Smuzhiyun goto out;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun if (!sil164_readb(dvo, SIL164_DID_LO, &ch))
158*4882a593Smuzhiyun goto out;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun if (ch != (SIL164_DID & 0xff)) {
161*4882a593Smuzhiyun DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
162*4882a593Smuzhiyun ch, adapter->name, dvo->slave_addr);
163*4882a593Smuzhiyun goto out;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun sil->quiet = false;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun DRM_DEBUG_KMS("init sil164 dvo controller successfully!\n");
168*4882a593Smuzhiyun return true;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun out:
171*4882a593Smuzhiyun kfree(sil);
172*4882a593Smuzhiyun return false;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
sil164_detect(struct intel_dvo_device * dvo)175*4882a593Smuzhiyun static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun u8 reg9;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun sil164_readb(dvo, SIL164_REG9, ®9);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun if (reg9 & SIL164_9_HTPLG)
182*4882a593Smuzhiyun return connector_status_connected;
183*4882a593Smuzhiyun else
184*4882a593Smuzhiyun return connector_status_disconnected;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
sil164_mode_valid(struct intel_dvo_device * dvo,struct drm_display_mode * mode)187*4882a593Smuzhiyun static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo,
188*4882a593Smuzhiyun struct drm_display_mode *mode)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun return MODE_OK;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
sil164_mode_set(struct intel_dvo_device * dvo,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)193*4882a593Smuzhiyun static void sil164_mode_set(struct intel_dvo_device *dvo,
194*4882a593Smuzhiyun const struct drm_display_mode *mode,
195*4882a593Smuzhiyun const struct drm_display_mode *adjusted_mode)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun /* As long as the basics are set up, since we don't have clock
198*4882a593Smuzhiyun * dependencies in the mode setup, we can just leave the
199*4882a593Smuzhiyun * registers alone and everything will work fine.
200*4882a593Smuzhiyun */
201*4882a593Smuzhiyun /* recommended programming sequence from doc */
202*4882a593Smuzhiyun /*sil164_writeb(sil, 0x08, 0x30);
203*4882a593Smuzhiyun sil164_writeb(sil, 0x09, 0x00);
204*4882a593Smuzhiyun sil164_writeb(sil, 0x0a, 0x90);
205*4882a593Smuzhiyun sil164_writeb(sil, 0x0c, 0x89);
206*4882a593Smuzhiyun sil164_writeb(sil, 0x08, 0x31);*/
207*4882a593Smuzhiyun /* don't do much */
208*4882a593Smuzhiyun return;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun /* set the SIL164 power state */
sil164_dpms(struct intel_dvo_device * dvo,bool enable)212*4882a593Smuzhiyun static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun int ret;
215*4882a593Smuzhiyun unsigned char ch;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun ret = sil164_readb(dvo, SIL164_REG8, &ch);
218*4882a593Smuzhiyun if (ret == false)
219*4882a593Smuzhiyun return;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun if (enable)
222*4882a593Smuzhiyun ch |= SIL164_8_PD;
223*4882a593Smuzhiyun else
224*4882a593Smuzhiyun ch &= ~SIL164_8_PD;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun sil164_writeb(dvo, SIL164_REG8, ch);
227*4882a593Smuzhiyun return;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
sil164_get_hw_state(struct intel_dvo_device * dvo)230*4882a593Smuzhiyun static bool sil164_get_hw_state(struct intel_dvo_device *dvo)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun int ret;
233*4882a593Smuzhiyun unsigned char ch;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun ret = sil164_readb(dvo, SIL164_REG8, &ch);
236*4882a593Smuzhiyun if (ret == false)
237*4882a593Smuzhiyun return false;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun if (ch & SIL164_8_PD)
240*4882a593Smuzhiyun return true;
241*4882a593Smuzhiyun else
242*4882a593Smuzhiyun return false;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
sil164_dump_regs(struct intel_dvo_device * dvo)245*4882a593Smuzhiyun static void sil164_dump_regs(struct intel_dvo_device *dvo)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun u8 val;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun sil164_readb(dvo, SIL164_FREQ_LO, &val);
250*4882a593Smuzhiyun DRM_DEBUG_KMS("SIL164_FREQ_LO: 0x%02x\n", val);
251*4882a593Smuzhiyun sil164_readb(dvo, SIL164_FREQ_HI, &val);
252*4882a593Smuzhiyun DRM_DEBUG_KMS("SIL164_FREQ_HI: 0x%02x\n", val);
253*4882a593Smuzhiyun sil164_readb(dvo, SIL164_REG8, &val);
254*4882a593Smuzhiyun DRM_DEBUG_KMS("SIL164_REG8: 0x%02x\n", val);
255*4882a593Smuzhiyun sil164_readb(dvo, SIL164_REG9, &val);
256*4882a593Smuzhiyun DRM_DEBUG_KMS("SIL164_REG9: 0x%02x\n", val);
257*4882a593Smuzhiyun sil164_readb(dvo, SIL164_REGC, &val);
258*4882a593Smuzhiyun DRM_DEBUG_KMS("SIL164_REGC: 0x%02x\n", val);
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
sil164_destroy(struct intel_dvo_device * dvo)261*4882a593Smuzhiyun static void sil164_destroy(struct intel_dvo_device *dvo)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun struct sil164_priv *sil = dvo->dev_priv;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun if (sil) {
266*4882a593Smuzhiyun kfree(sil);
267*4882a593Smuzhiyun dvo->dev_priv = NULL;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun const struct intel_dvo_dev_ops sil164_ops = {
272*4882a593Smuzhiyun .init = sil164_init,
273*4882a593Smuzhiyun .detect = sil164_detect,
274*4882a593Smuzhiyun .mode_valid = sil164_mode_valid,
275*4882a593Smuzhiyun .mode_set = sil164_mode_set,
276*4882a593Smuzhiyun .dpms = sil164_dpms,
277*4882a593Smuzhiyun .get_hw_state = sil164_get_hw_state,
278*4882a593Smuzhiyun .dump_regs = sil164_dump_regs,
279*4882a593Smuzhiyun .destroy = sil164_destroy,
280*4882a593Smuzhiyun };
281