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