• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * linux/drivers/video/savage/savagefb-i2c.c - S3 Savage DDC2
3  *
4  * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>
5  *
6  * Based partly on rivafb-i2c.c
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License.  See the file COPYING in the main directory of this archive
10  * for more details.
11  */
12 
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/delay.h>
16 #include <linux/pci.h>
17 #include <linux/fb.h>
18 
19 #include <asm/io.h>
20 #include "savagefb.h"
21 
22 #define SAVAGE_DDC 	0x50
23 
24 #define VGA_CR_IX	0x3d4
25 #define VGA_CR_DATA	0x3d5
26 
27 #define CR_SERIAL1	0xa0	/* I2C serial communications interface */
28 #define MM_SERIAL1	0xff20
29 #define CR_SERIAL2	0xb1	/* DDC2 monitor communications interface */
30 
31 /* based on vt8365 documentation */
32 #define PROSAVAGE_I2C_ENAB	0x10
33 #define PROSAVAGE_I2C_SCL_OUT	0x01
34 #define PROSAVAGE_I2C_SDA_OUT	0x02
35 #define PROSAVAGE_I2C_SCL_IN	0x04
36 #define PROSAVAGE_I2C_SDA_IN	0x08
37 
38 #define SAVAGE4_I2C_ENAB	0x00000020
39 #define SAVAGE4_I2C_SCL_OUT	0x00000001
40 #define SAVAGE4_I2C_SDA_OUT	0x00000002
41 #define SAVAGE4_I2C_SCL_IN	0x00000008
42 #define SAVAGE4_I2C_SDA_IN	0x00000010
43 
savage4_gpio_setscl(void * data,int val)44 static void savage4_gpio_setscl(void *data, int val)
45 {
46 	struct savagefb_i2c_chan *chan = data;
47 	unsigned int r;
48 
49 	r = readl(chan->ioaddr + chan->reg);
50 	if(val)
51 		r |= SAVAGE4_I2C_SCL_OUT;
52 	else
53 		r &= ~SAVAGE4_I2C_SCL_OUT;
54 	writel(r, chan->ioaddr + chan->reg);
55 	readl(chan->ioaddr + chan->reg);	/* flush posted write */
56 }
57 
savage4_gpio_setsda(void * data,int val)58 static void savage4_gpio_setsda(void *data, int val)
59 {
60 	struct savagefb_i2c_chan *chan = data;
61 
62 	unsigned int r;
63 	r = readl(chan->ioaddr + chan->reg);
64 	if(val)
65 		r |= SAVAGE4_I2C_SDA_OUT;
66 	else
67 		r &= ~SAVAGE4_I2C_SDA_OUT;
68 	writel(r, chan->ioaddr + chan->reg);
69 	readl(chan->ioaddr + chan->reg);	/* flush posted write */
70 }
71 
savage4_gpio_getscl(void * data)72 static int savage4_gpio_getscl(void *data)
73 {
74 	struct savagefb_i2c_chan *chan = data;
75 
76 	return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SCL_IN));
77 }
78 
savage4_gpio_getsda(void * data)79 static int savage4_gpio_getsda(void *data)
80 {
81 	struct savagefb_i2c_chan *chan = data;
82 
83 	return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SDA_IN));
84 }
85 
prosavage_gpio_setscl(void * data,int val)86 static void prosavage_gpio_setscl(void* data, int val)
87 {
88 	struct savagefb_i2c_chan *chan = data;
89 	u32			  r;
90 
91 	r = VGArCR(chan->reg, chan->par);
92 	r |= PROSAVAGE_I2C_ENAB;
93 	if (val) {
94 		r |= PROSAVAGE_I2C_SCL_OUT;
95 	} else {
96 		r &= ~PROSAVAGE_I2C_SCL_OUT;
97 	}
98 
99 	VGAwCR(chan->reg, r, chan->par);
100 }
101 
prosavage_gpio_setsda(void * data,int val)102 static void prosavage_gpio_setsda(void* data, int val)
103 {
104 	struct savagefb_i2c_chan *chan = data;
105 	unsigned int r;
106 
107 	r = VGArCR(chan->reg, chan->par);
108 	r |= PROSAVAGE_I2C_ENAB;
109 	if (val) {
110 		r |= PROSAVAGE_I2C_SDA_OUT;
111 	} else {
112 		r &= ~PROSAVAGE_I2C_SDA_OUT;
113 	}
114 
115 	VGAwCR(chan->reg, r, chan->par);
116 }
117 
prosavage_gpio_getscl(void * data)118 static int prosavage_gpio_getscl(void* data)
119 {
120 	struct savagefb_i2c_chan *chan = data;
121 
122 	return (VGArCR(chan->reg, chan->par) & PROSAVAGE_I2C_SCL_IN) ? 1 : 0;
123 }
124 
prosavage_gpio_getsda(void * data)125 static int prosavage_gpio_getsda(void* data)
126 {
127 	struct savagefb_i2c_chan *chan = data;
128 
129 	return (VGArCR(chan->reg, chan->par) & PROSAVAGE_I2C_SDA_IN) ? 1 : 0;
130 }
131 
savage_setup_i2c_bus(struct savagefb_i2c_chan * chan,const char * name)132 static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
133 				const char *name)
134 {
135 	int rc = 0;
136 
137 	if (chan->par) {
138 		strcpy(chan->adapter.name, name);
139 		chan->adapter.owner		= THIS_MODULE;
140 		chan->adapter.algo_data		= &chan->algo;
141 		chan->adapter.dev.parent	= &chan->par->pcidev->dev;
142 		chan->algo.udelay		= 10;
143 		chan->algo.timeout		= 20;
144 		chan->algo.data 		= chan;
145 
146 		i2c_set_adapdata(&chan->adapter, chan);
147 
148 		/* Raise SCL and SDA */
149 		chan->algo.setsda(chan, 1);
150 		chan->algo.setscl(chan, 1);
151 		udelay(20);
152 
153 		rc = i2c_bit_add_bus(&chan->adapter);
154 
155 		if (rc == 0)
156 			dev_dbg(&chan->par->pcidev->dev,
157 				"I2C bus %s registered.\n", name);
158 		else
159 			dev_warn(&chan->par->pcidev->dev,
160 				 "Failed to register I2C bus %s.\n", name);
161 	} else
162 		chan->par = NULL;
163 
164 	return rc;
165 }
166 
savagefb_create_i2c_busses(struct fb_info * info)167 void savagefb_create_i2c_busses(struct fb_info *info)
168 {
169 	struct savagefb_par *par = info->par;
170 	par->chan.par	= par;
171 
172 	switch(info->fix.accel) {
173 	case FB_ACCEL_PROSAVAGE_DDRK:
174 	case FB_ACCEL_PROSAVAGE_PM:
175 		par->chan.reg         = CR_SERIAL2;
176 		par->chan.ioaddr      = par->mmio.vbase;
177 		par->chan.algo.setsda = prosavage_gpio_setsda;
178 		par->chan.algo.setscl = prosavage_gpio_setscl;
179 		par->chan.algo.getsda = prosavage_gpio_getsda;
180 		par->chan.algo.getscl = prosavage_gpio_getscl;
181 		break;
182 	case FB_ACCEL_SAVAGE4:
183 	case FB_ACCEL_SAVAGE2000:
184 		par->chan.reg         = 0xff20;
185 		par->chan.ioaddr      = par->mmio.vbase;
186 		par->chan.algo.setsda = savage4_gpio_setsda;
187 		par->chan.algo.setscl = savage4_gpio_setscl;
188 		par->chan.algo.getsda = savage4_gpio_getsda;
189 		par->chan.algo.getscl = savage4_gpio_getscl;
190 		break;
191 	default:
192 		par->chan.par = NULL;
193 	}
194 
195 	savage_setup_i2c_bus(&par->chan, "SAVAGE DDC2");
196 }
197 
savagefb_delete_i2c_busses(struct fb_info * info)198 void savagefb_delete_i2c_busses(struct fb_info *info)
199 {
200 	struct savagefb_par *par = info->par;
201 
202 	if (par->chan.par)
203 		i2c_del_adapter(&par->chan.adapter);
204 
205 	par->chan.par = NULL;
206 }
207 
savagefb_probe_i2c_connector(struct fb_info * info,u8 ** out_edid)208 int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid)
209 {
210 	struct savagefb_par *par = info->par;
211 	u8 *edid;
212 
213 	if (par->chan.par)
214 		edid = fb_ddc_read(&par->chan.adapter);
215 	else
216 		edid = NULL;
217 
218 	if (!edid) {
219 		/* try to get from firmware */
220 		const u8 *e = fb_firmware_edid(info->device);
221 
222 		if (e)
223 			edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
224 	}
225 
226 	*out_edid = edid;
227 
228 	return (edid) ? 0 : 1;
229 }
230 
231 MODULE_LICENSE("GPL");
232