Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
489 | giacomo | 1 | /* |
2 | * |
||
3 | * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. |
||
4 | * |
||
5 | * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> |
||
6 | * |
||
7 | * Version: 1.64 2002/06/10 |
||
8 | * |
||
9 | * See matroxfb_base.c for contributors. |
||
10 | * |
||
11 | */ |
||
12 | |||
13 | #include "matroxfb_base.h" |
||
14 | #include "matroxfb_maven.h" |
||
15 | #include <linux/i2c.h> |
||
16 | #include <linux/i2c-algo-bit.h> |
||
17 | |||
18 | /* MGA-TVO I2C for G200, G400 */ |
||
19 | #define MAT_CLK 0x20 |
||
20 | #define MAT_DATA 0x10 |
||
21 | /* primary head DDC for Mystique(?), G100, G200, G400 */ |
||
22 | #define DDC1_CLK 0x08 |
||
23 | #define DDC1_DATA 0x02 |
||
24 | /* primary head DDC for Millennium, Millennium II */ |
||
25 | #define DDC1B_CLK 0x10 |
||
26 | #define DDC1B_DATA 0x04 |
||
27 | /* secondary head DDC for G400 */ |
||
28 | #define DDC2_CLK 0x04 |
||
29 | #define DDC2_DATA 0x01 |
||
30 | |||
31 | /******************************************************/ |
||
32 | |||
33 | struct matroxfb_dh_maven_info { |
||
34 | struct i2c_bit_adapter maven; |
||
35 | struct i2c_bit_adapter ddc1; |
||
36 | struct i2c_bit_adapter ddc2; |
||
37 | }; |
||
38 | |||
39 | static int matroxfb_read_gpio(struct matrox_fb_info* minfo) { |
||
40 | unsigned long flags; |
||
41 | int v; |
||
42 | |||
43 | matroxfb_DAC_lock_irqsave(flags); |
||
44 | v = matroxfb_DAC_in(PMINFO DAC_XGENIODATA); |
||
45 | matroxfb_DAC_unlock_irqrestore(flags); |
||
46 | return v; |
||
47 | } |
||
48 | |||
49 | static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) { |
||
50 | unsigned long flags; |
||
51 | int v; |
||
52 | |||
53 | matroxfb_DAC_lock_irqsave(flags); |
||
54 | v = (matroxfb_DAC_in(PMINFO DAC_XGENIOCTRL) & mask) | val; |
||
55 | matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, v); |
||
56 | /* We must reset GENIODATA very often... XFree plays with this register */ |
||
57 | matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0x00); |
||
58 | matroxfb_DAC_unlock_irqrestore(flags); |
||
59 | } |
||
60 | |||
61 | /* software I2C functions */ |
||
62 | static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) { |
||
63 | if (state) |
||
64 | state = 0; |
||
65 | else |
||
66 | state = mask; |
||
67 | matroxfb_set_gpio(minfo, ~mask, state); |
||
68 | } |
||
69 | |||
70 | static void matroxfb_gpio_setsda(void* data, int state) { |
||
71 | struct i2c_bit_adapter* b = data; |
||
72 | matroxfb_i2c_set(b->minfo, b->mask.data, state); |
||
73 | } |
||
74 | |||
75 | static void matroxfb_gpio_setscl(void* data, int state) { |
||
76 | struct i2c_bit_adapter* b = data; |
||
77 | matroxfb_i2c_set(b->minfo, b->mask.clock, state); |
||
78 | } |
||
79 | |||
80 | static int matroxfb_gpio_getsda(void* data) { |
||
81 | struct i2c_bit_adapter* b = data; |
||
82 | return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0; |
||
83 | } |
||
84 | |||
85 | static int matroxfb_gpio_getscl(void* data) { |
||
86 | struct i2c_bit_adapter* b = data; |
||
87 | return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0; |
||
88 | } |
||
89 | |||
90 | static struct i2c_adapter matrox_i2c_adapter_template = |
||
91 | { |
||
92 | .owner = THIS_MODULE, |
||
93 | .id = I2C_HW_B_G400, |
||
94 | }; |
||
95 | |||
96 | static struct i2c_algo_bit_data matrox_i2c_algo_template = |
||
97 | { |
||
98 | NULL, |
||
99 | matroxfb_gpio_setsda, |
||
100 | matroxfb_gpio_setscl, |
||
101 | matroxfb_gpio_getsda, |
||
102 | matroxfb_gpio_getscl, |
||
103 | 10, 10, 100, |
||
104 | }; |
||
105 | |||
106 | static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, |
||
107 | unsigned int data, unsigned int clock, const char* name) { |
||
108 | int err; |
||
109 | |||
110 | b->minfo = minfo; |
||
111 | b->mask.data = data; |
||
112 | b->mask.clock = clock; |
||
113 | b->adapter = matrox_i2c_adapter_template; |
||
114 | snprintf(b->adapter.name, I2C_NAME_SIZE, name, |
||
115 | minfo->fbcon.node); |
||
116 | i2c_set_adapdata(&b->adapter, b); |
||
117 | b->adapter.algo_data = &b->bac; |
||
118 | b->bac = matrox_i2c_algo_template; |
||
119 | b->bac.data = b; |
||
120 | err = i2c_bit_add_bus(&b->adapter); |
||
121 | b->initialized = !err; |
||
122 | return err; |
||
123 | } |
||
124 | |||
125 | static void i2c_bit_bus_del(struct i2c_bit_adapter* b) { |
||
126 | if (b->initialized) { |
||
127 | i2c_bit_del_bus(&b->adapter); |
||
128 | b->initialized = 0; |
||
129 | } |
||
130 | } |
||
131 | |||
132 | static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) { |
||
133 | i2c_bit_bus_del(&minfo2->maven); |
||
134 | } |
||
135 | |||
136 | static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) { |
||
137 | i2c_bit_bus_del(&minfo2->ddc1); |
||
138 | } |
||
139 | |||
140 | static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) { |
||
141 | i2c_bit_bus_del(&minfo2->ddc2); |
||
142 | } |
||
143 | |||
144 | static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) { |
||
145 | int err; |
||
146 | unsigned long flags; |
||
147 | struct matroxfb_dh_maven_info* m2info; |
||
148 | |||
149 | m2info = (struct matroxfb_dh_maven_info*)kmalloc(sizeof(*m2info), GFP_KERNEL); |
||
150 | if (!m2info) |
||
151 | return NULL; |
||
152 | |||
153 | matroxfb_DAC_lock_irqsave(flags); |
||
154 | matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0xFF); |
||
155 | matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0x00); |
||
156 | matroxfb_DAC_unlock_irqrestore(flags); |
||
157 | |||
158 | memset(m2info, 0, sizeof(*m2info)); |
||
159 | |||
160 | switch (ACCESS_FBINFO(chip)) { |
||
161 | case MGA_2064: |
||
162 | case MGA_2164: |
||
163 | err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0"); |
||
164 | break; |
||
165 | default: |
||
166 | err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0"); |
||
167 | break; |
||
168 | } |
||
169 | if (err) |
||
170 | goto fail_ddc1; |
||
171 | if (ACCESS_FBINFO(devflags.dualhead)) { |
||
172 | err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1"); |
||
173 | if (err == -ENODEV) { |
||
174 | printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n"); |
||
175 | } else if (err) |
||
176 | printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n"); |
||
177 | /* Register maven bus even on G450/G550 */ |
||
178 | err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, "MAVEN:fb%u"); |
||
179 | if (err) |
||
180 | printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n"); |
||
181 | } |
||
182 | return m2info; |
||
183 | fail_ddc1:; |
||
184 | kfree(m2info); |
||
185 | printk(KERN_ERR "i2c-matroxfb: Could not register primary adapter DDC bus.\n"); |
||
186 | return NULL; |
||
187 | } |
||
188 | |||
189 | static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) { |
||
190 | struct matroxfb_dh_maven_info* m2info = data; |
||
191 | |||
192 | i2c_maven_done(m2info); |
||
193 | i2c_ddc2_done(m2info); |
||
194 | i2c_ddc1_done(m2info); |
||
195 | kfree(m2info); |
||
196 | } |
||
197 | |||
198 | static struct matroxfb_driver i2c_matroxfb = { |
||
199 | .node = LIST_HEAD_INIT(i2c_matroxfb.node), |
||
200 | .name = "i2c-matroxfb", |
||
201 | .probe = i2c_matroxfb_probe, |
||
202 | .remove = i2c_matroxfb_remove, |
||
203 | }; |
||
204 | |||
205 | static int __init i2c_matroxfb_init(void) { |
||
206 | if (matroxfb_register_driver(&i2c_matroxfb)) { |
||
207 | printk(KERN_ERR "i2c-matroxfb: failed to register driver\n"); |
||
208 | return -ENXIO; |
||
209 | } |
||
210 | return 0; |
||
211 | } |
||
212 | |||
213 | static void __exit i2c_matroxfb_exit(void) { |
||
214 | matroxfb_unregister_driver(&i2c_matroxfb); |
||
215 | } |
||
216 | |||
217 | MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); |
||
218 | MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards"); |
||
219 | |||
220 | module_init(i2c_matroxfb_init); |
||
221 | module_exit(i2c_matroxfb_exit); |
||
222 | /* no __setup required */ |
||
223 | MODULE_LICENSE("GPL"); |