1fa225cbcSrjs/* -*- c-basic-offset: 4 -*- */
2fa225cbcSrjs/*
3fa225cbcSrjs * Copyright © 2007 Dave Mueller
4fa225cbcSrjs *
5fa225cbcSrjs * Permission is hereby granted, free of charge, to any person obtaining a
6fa225cbcSrjs * copy of this software and associated documentation files (the "Software"),
7fa225cbcSrjs * to deal in the Software without restriction, including without limitation
8fa225cbcSrjs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9fa225cbcSrjs * and/or sell copies of the Software, and to permit persons to whom the
10fa225cbcSrjs * Software is furnished to do so, subject to the following conditions:
11fa225cbcSrjs *
12fa225cbcSrjs * The above copyright notice and this permission notice (including the next
13fa225cbcSrjs * paragraph) shall be included in all copies or substantial portions of the
14fa225cbcSrjs * Software.
15fa225cbcSrjs *
16fa225cbcSrjs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17fa225cbcSrjs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18fa225cbcSrjs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19fa225cbcSrjs * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20fa225cbcSrjs * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21fa225cbcSrjs * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22fa225cbcSrjs * IN THE SOFTWARE.
23fa225cbcSrjs *
24fa225cbcSrjs * Authors:
25fa225cbcSrjs *    Dave Mueller <dave.mueller@gmx.ch>
26fa225cbcSrjs *
27fa225cbcSrjs */
28fa225cbcSrjs
29fa225cbcSrjs#ifdef HAVE_CONFIG_H
30fa225cbcSrjs#include "config.h"
31fa225cbcSrjs#endif
32fa225cbcSrjs
33fa225cbcSrjs#include <stdint.h>
34fa225cbcSrjs
35fa225cbcSrjs#include "xf86.h"
36fa225cbcSrjs#include "xf86_OSproc.h"
37fa225cbcSrjs#include "compiler.h"
38fa225cbcSrjs#include "miscstruct.h"
39fa225cbcSrjs#include "xf86i2c.h"
40fa225cbcSrjs#include "xf86Crtc.h"
41fa225cbcSrjs#ifdef HAVE_XEXTPROTO_71
42fa225cbcSrjs#include <X11/extensions/dpmsconst.h>
43fa225cbcSrjs#else
44fa225cbcSrjs#define DPMS_SERVER
45fa225cbcSrjs#include <X11/extensions/dpms.h>
46fa225cbcSrjs#endif
47fa225cbcSrjs
48fa225cbcSrjs
49fa225cbcSrjs#include "../i2c_vid.h"
50fa225cbcSrjs#include "tfp410.h"
51fa225cbcSrjs#include "tfp410_reg.h"
52fa225cbcSrjs
53fa225cbcSrjstypedef struct _TFP410SaveRec {
54fa225cbcSrjs    uint8_t ctl1;
55fa225cbcSrjs    uint8_t ctl2;
56fa225cbcSrjs} TFP410SaveRec;
57fa225cbcSrjs
58fa225cbcSrjstypedef struct {
59fa225cbcSrjs    I2CDevRec d;
60fa225cbcSrjs    Bool quiet;
61fa225cbcSrjs
62fa225cbcSrjs    TFP410SaveRec SavedReg;
63fa225cbcSrjs    TFP410SaveRec ModeReg;
64fa225cbcSrjs} TFP410Rec, *TFP410Ptr;
65fa225cbcSrjs
66fa225cbcSrjs#define TFPPTR(d) ((TFP410Ptr)(d->DriverPrivate.ptr))
67fa225cbcSrjs
68fa225cbcSrjsstatic Bool
69fa225cbcSrjstfp410ReadByte(TFP410Ptr tfp, int addr, uint8_t *ch)
70fa225cbcSrjs{
71fa225cbcSrjs    if (!xf86I2CReadByte(&(tfp->d), addr, ch)) {
72fa225cbcSrjs	if (!tfp->quiet) {
73fa225cbcSrjs	    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR,
74fa225cbcSrjs		       "Unable to read from %s Slave %d.\n",
75fa225cbcSrjs		       tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr);
76fa225cbcSrjs	}
77fa225cbcSrjs	return FALSE;
78fa225cbcSrjs    }
79fa225cbcSrjs    return TRUE;
80fa225cbcSrjs}
81fa225cbcSrjs
82fa225cbcSrjsstatic Bool
83fa225cbcSrjstfp410WriteByte(TFP410Ptr tfp, int addr, uint8_t ch)
84fa225cbcSrjs{
85fa225cbcSrjs    if (!xf86I2CWriteByte(&(tfp->d), addr, ch)) {
86fa225cbcSrjs	if (!tfp->quiet) {
87fa225cbcSrjs	    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR,
88fa225cbcSrjs		       "Unable to write to %s Slave %d.\n",
89fa225cbcSrjs		       tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr);
90fa225cbcSrjs	}
91fa225cbcSrjs	return FALSE;
92fa225cbcSrjs    }
93fa225cbcSrjs    return TRUE;
94fa225cbcSrjs}
95fa225cbcSrjs
96fa225cbcSrjsstatic int
97fa225cbcSrjstfp410GetID(TFP410Ptr tfp, int addr)
98fa225cbcSrjs{
99fa225cbcSrjs    unsigned char ch1, ch2;
100fa225cbcSrjs
101fa225cbcSrjs    if (tfp410ReadByte(tfp, addr+0, &ch1) &&
102fa225cbcSrjs        tfp410ReadByte(tfp, addr+1, &ch2)) {
103fa225cbcSrjs
104fa225cbcSrjs	return ((ch2<<8) & 0xFF00) | (ch1 & 0x00FF);
105fa225cbcSrjs    }
106fa225cbcSrjs    return -1;
107fa225cbcSrjs}
108fa225cbcSrjs
109fa225cbcSrjs/* Ti TFP410 driver for chip on i2c bus */
110fa225cbcSrjsstatic void *
111fa225cbcSrjstfp410_init(I2CBusPtr b, I2CSlaveAddr addr)
112fa225cbcSrjs{
113fa225cbcSrjs    /* this will detect the tfp410 chip on the specified i2c bus */
114fa225cbcSrjs    TFP410Ptr tfp;
115fa225cbcSrjs    int id;
116fa225cbcSrjs
117fa225cbcSrjs    tfp = xcalloc(1, sizeof(TFP410Rec));
118fa225cbcSrjs    if (tfp == NULL)
119fa225cbcSrjs	return NULL;
120fa225cbcSrjs
121fa225cbcSrjs    tfp->d.DevName = "TFP410 TMDS Controller";
122fa225cbcSrjs    tfp->d.SlaveAddr = addr;
123fa225cbcSrjs    tfp->d.pI2CBus = b;
124fa225cbcSrjs    tfp->d.StartTimeout = b->StartTimeout;
125fa225cbcSrjs    tfp->d.BitTimeout = b->BitTimeout;
126fa225cbcSrjs    tfp->d.AcknTimeout = b->AcknTimeout;
127fa225cbcSrjs    tfp->d.ByteTimeout = b->ByteTimeout;
128fa225cbcSrjs    tfp->d.DriverPrivate.ptr = tfp;
129fa225cbcSrjs    tfp->quiet = TRUE;
130fa225cbcSrjs
131fa225cbcSrjs    if ((id = tfp410GetID(tfp, TFP410_VID_LO)) != TFP410_VID) {
132fa225cbcSrjs	if (id != 0xffffffff) {
133fa225cbcSrjs	    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR,
134fa225cbcSrjs		       "tfp410 not detected got VID %X: from %s Slave %d.\n",
135fa225cbcSrjs		       id, tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr);
136fa225cbcSrjs	}
137fa225cbcSrjs	goto out;
138fa225cbcSrjs    }
139fa225cbcSrjs
140fa225cbcSrjs    if ((id = tfp410GetID(tfp, TFP410_DID_LO)) != TFP410_DID) {
141fa225cbcSrjs	xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR,
142fa225cbcSrjs		   "tfp410 not detected got DID %X: from %s Slave %d.\n",
143fa225cbcSrjs		   id, tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr);
144fa225cbcSrjs	goto out;
145fa225cbcSrjs    }
146fa225cbcSrjs    tfp->quiet = FALSE;
147fa225cbcSrjs
148fa225cbcSrjs    if (!xf86I2CDevInit(&(tfp->d))) {
149fa225cbcSrjs	goto out;
150fa225cbcSrjs    }
151fa225cbcSrjs
152fa225cbcSrjs    return tfp;
153fa225cbcSrjs
154fa225cbcSrjsout:
155fa225cbcSrjs    xfree(tfp);
156fa225cbcSrjs    return NULL;
157fa225cbcSrjs}
158fa225cbcSrjs
159fa225cbcSrjsstatic xf86OutputStatus
160fa225cbcSrjstfp410_detect(I2CDevPtr d)
161fa225cbcSrjs{
162fa225cbcSrjs    TFP410Ptr tfp = TFPPTR(d);
163fa225cbcSrjs    xf86OutputStatus ret = XF86OutputStatusDisconnected;
164fa225cbcSrjs    unsigned char ctl2;
165fa225cbcSrjs
166fa225cbcSrjs    if (tfp410ReadByte(tfp, TFP410_CTL_2, &ctl2)) {
167fa225cbcSrjs	if (ctl2 & TFP410_CTL_2_HTPLG)
168fa225cbcSrjs	    ret = XF86OutputStatusConnected;
169fa225cbcSrjs	else
170fa225cbcSrjs	    ret = XF86OutputStatusDisconnected;
171fa225cbcSrjs    }
172fa225cbcSrjs
173fa225cbcSrjs    return ret;
174fa225cbcSrjs}
175fa225cbcSrjs
176fa225cbcSrjsstatic ModeStatus
177fa225cbcSrjstfp410_mode_valid(I2CDevPtr d, DisplayModePtr mode)
178fa225cbcSrjs{
179fa225cbcSrjs    return MODE_OK;
180fa225cbcSrjs}
181fa225cbcSrjs
182fa225cbcSrjsstatic void
183fa225cbcSrjstfp410_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode)
184fa225cbcSrjs{
185fa225cbcSrjs    /* As long as the basics are set up, since we don't have clock dependencies
186fa225cbcSrjs     * in the mode setup, we can just leave the registers alone and everything
187fa225cbcSrjs     * will work fine.
188fa225cbcSrjs     */
189fa225cbcSrjs    /* don't do much */
190fa225cbcSrjs    return;
191fa225cbcSrjs}
192fa225cbcSrjs
193fa225cbcSrjs/* set the tfp410 power state */
194fa225cbcSrjsstatic void
195fa225cbcSrjstfp410_dpms(I2CDevPtr d, int mode)
196fa225cbcSrjs{
197fa225cbcSrjs    TFP410Ptr tfp = TFPPTR(d);
198fa225cbcSrjs    unsigned char ctl1;
199fa225cbcSrjs
200fa225cbcSrjs    if (!tfp410ReadByte(tfp, TFP410_CTL_1, &ctl1))
201fa225cbcSrjs	return;
202fa225cbcSrjs
203fa225cbcSrjs    if (mode == DPMSModeOn)
204fa225cbcSrjs	ctl1 |= TFP410_CTL_1_PD;
205fa225cbcSrjs    else
206fa225cbcSrjs	ctl1 &= ~TFP410_CTL_1_PD;
207fa225cbcSrjs
208fa225cbcSrjs    tfp410WriteByte(tfp, TFP410_CTL_1, ctl1);
209fa225cbcSrjs}
210fa225cbcSrjs
211fa225cbcSrjsstatic void
212fa225cbcSrjstfp410_dump_regs(I2CDevPtr d)
213fa225cbcSrjs{
214fa225cbcSrjs    TFP410Ptr tfp = TFPPTR(d);
215fa225cbcSrjs    uint8_t val, val2;
216fa225cbcSrjs
217fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_REV, &val);
218fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
219fa225cbcSrjs	       "TFP410_REV: 0x%02X\n", val);
220fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_CTL_1, &val);
221fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
222fa225cbcSrjs	       "TFP410_CTL1: 0x%02X\n", val);
223fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_CTL_2, &val);
224fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
225fa225cbcSrjs	       "TFP410_CTL2: 0x%02X\n", val);
226fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_CTL_3, &val);
227fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
228fa225cbcSrjs	       "TFP410_CTL3: 0x%02X\n", val);
229fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_USERCFG, &val);
230fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
231fa225cbcSrjs	       "TFP410_USERCFG: 0x%02X\n", val);
232fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_DE_DLY, &val);
233fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
234fa225cbcSrjs	       "TFP410_DE_DLY: 0x%02X\n", val);
235fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_DE_CTL, &val);
236fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
237fa225cbcSrjs	       "TFP410_DE_CTL: 0x%02X\n", val);
238fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_DE_TOP, &val);
239fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
240fa225cbcSrjs	       "TFP410_DE_TOP: 0x%02X\n", val);
241fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_DE_CNT_LO, &val);
242fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_DE_CNT_HI, &val2);
243fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
244fa225cbcSrjs	       "TFP410_DE_CNT: 0x%02X%02X\n", val2, val);
245fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_DE_LIN_LO, &val);
246fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_DE_LIN_HI, &val2);
247fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
248fa225cbcSrjs	       "TFP410_DE_LIN: 0x%02X%02X\n", val2, val);
249fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_H_RES_LO, &val);
250fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_H_RES_HI, &val2);
251fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
252fa225cbcSrjs	       "TFP410_H_RES: 0x%02X%02X\n", val2, val);
253fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_V_RES_LO, &val);
254fa225cbcSrjs    tfp410ReadByte(tfp, TFP410_V_RES_HI, &val2);
255fa225cbcSrjs    xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO,
256fa225cbcSrjs	       "TFP410_V_RES: 0x%02X%02X\n", val2, val);
257fa225cbcSrjs}
258fa225cbcSrjs
259fa225cbcSrjsstatic void
260fa225cbcSrjstfp410_save(I2CDevPtr d)
261fa225cbcSrjs{
262fa225cbcSrjs    TFP410Ptr tfp = TFPPTR(d);
263fa225cbcSrjs
264fa225cbcSrjs    if (!tfp410ReadByte(tfp, TFP410_CTL_1, &tfp->SavedReg.ctl1))
265fa225cbcSrjs	return;
266fa225cbcSrjs
267fa225cbcSrjs    if (!tfp410ReadByte(tfp, TFP410_CTL_2, &tfp->SavedReg.ctl2))
268fa225cbcSrjs	return;
269fa225cbcSrjs}
270fa225cbcSrjs
271fa225cbcSrjsstatic void
272fa225cbcSrjstfp410_restore(I2CDevPtr d)
273fa225cbcSrjs{
274fa225cbcSrjs    TFP410Ptr tfp = TFPPTR(d);
275fa225cbcSrjs
276fa225cbcSrjs    /* Restore it powered down initially */
277fa225cbcSrjs    tfp410WriteByte(tfp, TFP410_CTL_1, tfp->SavedReg.ctl1 & ~0x1);
278fa225cbcSrjs
279fa225cbcSrjs    tfp410WriteByte(tfp, TFP410_CTL_2, tfp->SavedReg.ctl2);
280fa225cbcSrjs    tfp410WriteByte(tfp, TFP410_CTL_1, tfp->SavedReg.ctl1);
281fa225cbcSrjs}
282fa225cbcSrjs
283fa225cbcSrjs_X_EXPORT I830I2CVidOutputRec TFP410VidOutput = {
284fa225cbcSrjs    .init = tfp410_init,
285fa225cbcSrjs    .detect = tfp410_detect,
286fa225cbcSrjs    .mode_valid = tfp410_mode_valid,
287fa225cbcSrjs    .mode_set = tfp410_mode_set,
288fa225cbcSrjs    .dpms = tfp410_dpms,
289fa225cbcSrjs    .dump_regs = tfp410_dump_regs,
290fa225cbcSrjs    .save = tfp410_save,
291fa225cbcSrjs    .restore = tfp410_restore,
292fa225cbcSrjs};
293