xref: /dragonfly/sys/dev/video/cxm/cxm_eeprom.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1 /*
2  * Copyright (c) 2003, 2004, 2005
3  *        John Wehle <john@feith.com>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *        This product includes software developed by John Wehle.
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.      IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * EEPROM routines for the Conexant MPEG-2 Codec driver.
34  *
35  * Ideally these routines should be implemented as a separate
36  * driver which has a generic EEPROM interface so that it's
37  * not necessary for each multimedia driver to re-invent the
38  * wheel.
39  */
40 
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/conf.h>
45 #include <sys/uio.h>
46 #include <sys/kernel.h>
47 #include <sys/poll.h>
48 #include <sys/select.h>
49 #include <sys/resource.h>
50 #include <sys/bus.h>
51 #include <sys/rman.h>
52 
53 
54 #include <machine/clock.h>
55 
56 #include <dev/video/cxm/cxm.h>
57 
58 #include <bus/iicbus/iiconf.h>
59 #include <bus/iicbus/iicbus.h>
60 
61 #include "iicbb_if.h"
62 
63 
64 static int
cxm_eeprom_read(device_t iicbus,int i2c_addr,char * buf,int len,unsigned int offset)65 cxm_eeprom_read(device_t iicbus, int i2c_addr,
66                      char *buf, int len, unsigned int offset)
67 {
68           char msg[1];
69           int received;
70           int sent;
71 
72           msg[0] = (unsigned char)offset;
73 
74           if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
75                     return -1;
76 
77           if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
78               || sent != sizeof(msg))
79                     goto fail;
80 
81           if (iicbus_repeated_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0)
82                     goto fail;
83 
84           if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0)
85                     goto fail;
86 
87           iicbus_stop(iicbus);
88 
89         return received;
90 
91 fail:
92           iicbus_stop(iicbus);
93           return -1;
94 }
95 
96 
97 int
cxm_eeprom_init(struct cxm_softc * sc)98 cxm_eeprom_init(struct cxm_softc *sc)
99 {
100           unsigned char eeprom[1];
101 
102           if (cxm_eeprom_read(sc->iicbus, CXM_I2C_EEPROM,
103                                   eeprom, sizeof(eeprom), 0) != sizeof(eeprom))
104                     return -1;
105 
106           return 0;
107 }
108 
109 
110 int
cxm_eeprom_tuner_type(struct cxm_softc * sc)111 cxm_eeprom_tuner_type(struct cxm_softc *sc)
112 {
113           unsigned char eeprom[256];
114           unsigned int i;
115           unsigned int len;
116           unsigned int subsystem_vendor_id;
117           unsigned int tuner_code;
118           int tuner_type;
119 
120           if (cxm_eeprom_read(sc->iicbus, CXM_I2C_EEPROM,
121                                   eeprom, sizeof(eeprom), 0) != sizeof(eeprom))
122                     return -1;
123 
124           subsystem_vendor_id = (unsigned int)eeprom[254] << 8 | eeprom[255];
125           tuner_type = -1;
126 
127           switch (subsystem_vendor_id) {
128           case PCI_VENDOR_HAUPPAUGE:
129 
130                     /*
131                      * The Hauppauge eeprom format is tagged.
132                      */
133 
134                     if (eeprom[0] != 0x84) {
135                               device_printf(sc->dev,
136                                   "unknown Hauppauge eeprom format %#x\n",
137                                   (unsigned int)eeprom[0]);
138                               break;
139                     }
140 
141                     tuner_code = -1;
142 
143                     for (i = 0; i < sizeof(eeprom); i += len) {
144                               len = 0;
145                               if (eeprom[i] == 0x84) {
146                                         len = (unsigned int)eeprom[i + 2] << 8
147                                               | eeprom[i + 1];
148                                         i += 3;
149                               } else if ((eeprom[i] & 0xf0) == 0x70) {
150                                         if (eeprom[i] & 0x08)
151                                                   break;
152                                         len = eeprom[i] & 0x07;
153                                         i++;
154                               } else {
155                                         device_printf(sc->dev,
156                                             "unknown Hauppauge eeprom packet %#x\n",
157                                             (unsigned int)eeprom[i]);
158                                         return -1;
159                               }
160 
161                               if (i >= sizeof(eeprom)
162                                   || (i + len) > sizeof(eeprom)) {
163                                         device_printf(sc->dev,
164                                             "corrupt Hauppauge eeprom packet\n");
165                                         return -1;
166                               }
167 
168                               switch (eeprom[i]) {
169                               case 0x00:
170                                         tuner_code = eeprom[i + 6];
171                                         break;
172 
173                               case 0x0a:
174                                         tuner_code = eeprom[i + 2];
175                                         break;
176 
177                               default:
178                                         break;
179                               }
180                     }
181 
182                     switch (tuner_code) {
183                     case 0x03: /* Philips FI1216 */
184                     case 0x08: /* Philips FI1216 MK2 */
185                               tuner_type = CXM_TUNER_PHILIPS_FI1216_MK2;
186                               break;
187 
188                     case 0x22: /* Philips FQ1216ME */
189                               tuner_type = CXM_TUNER_PHILIPS_FQ1216ME;
190                               break;
191 
192                     case 0x37: /* Philips FQ1216ME MK3 */
193                               tuner_type = CXM_TUNER_PHILIPS_FQ1216ME_MK3;
194                               break;
195 
196                     case 0x1d: /* Temic 4006FH5 */
197                               tuner_type = CXM_TUNER_TEMIC_4006_FH5;
198                               break;
199 
200                     case 0x30: /* LG Innotek TPI8PSB11D */
201                               tuner_type = CXM_TUNER_LG_TPI8PSB11D;
202                               break;
203 
204                     case 0x34: /* Microtune 4049FM5 */
205                               tuner_type = CXM_TUNER_MICROTUNE_4049_FM5;
206                               break;
207 
208                     case 0x05: /* Philips FI1236 */
209                     case 0x0a: /* Philips FI1236 MK2 */
210                               tuner_type = CXM_TUNER_PHILIPS_FI1236_MK2;
211                               break;
212 
213                     case 0x1a: /* Temic 4036FY5 */
214                               tuner_type = CXM_TUNER_TEMIC_4036_FY5;
215                               break;
216 
217                     case 0x52: /* LG Innotek TAPC-H701F */
218                               tuner_type = CXM_TUNER_LG_TAPC_H701F;
219                               break;
220 
221                     case 0x55: /* TCL 2002N-6A */
222                               tuner_type = CXM_TUNER_TCL_2002N_6A;
223                               break;
224 
225                     case 0x06: /* Philips FI1246 */
226                     case 0x0b: /* Philips FI1246 MK2 */
227                               tuner_type = CXM_TUNER_PHILIPS_FI1246_MK2;
228                               break;
229 
230                     case 0x23: /* Temic 4066FY5 */
231                               tuner_type = CXM_TUNER_TEMIC_4066_FY5;
232                               break;
233 
234                     case 0x10: /* Philips FR1216 MK2 */
235                     case 0x15: /* Philips FM1216 */
236                               tuner_type = CXM_TUNER_PHILIPS_FM1216;
237                               break;
238 
239                     case 0x39: /* Philips FM1216ME MK3 */
240                               tuner_type = CXM_TUNER_PHILIPS_FM1216ME_MK3;
241                               break;
242 
243                     case 0x2a: /* Temic 4009FR5 */
244                               tuner_type = CXM_TUNER_TEMIC_4009_FR5;
245                               break;
246 
247                     case 0x2f: /* LG Innotek TPI8PSB01N */
248                               tuner_type = CXM_TUNER_LG_TPI8PSB01N;
249                               break;
250 
251                     case 0x12: /* Philips FR1236 MK2 */
252                     case 0x17: /* Philips FM1236 */
253                               tuner_type = CXM_TUNER_PHILIPS_FM1236;
254                               break;
255 
256                     case 0x21: /* Temic 4039FR5 */
257                               tuner_type = CXM_TUNER_TEMIC_4039_FR5;
258                               break;
259 
260                     case 0x44: /* LG Innotek TAPE-H001F */
261                               tuner_type = CXM_TUNER_LG_TAPE_H001F;
262                               break;
263 
264                     case 0x13: /* Philips FR1246 MK2 */
265                     case 0x18: /* Philips FM1246 */
266                               tuner_type = CXM_TUNER_PHILIPS_FM1246;
267                               break;
268 
269                     default:
270                               device_printf(sc->dev, "unknown tuner code %#x\n",
271                                   tuner_code);
272                               break;
273                     }
274                     break;
275 
276           default:
277                     device_printf(sc->dev, "unknown subsystem vendor id %#x\n",
278                         subsystem_vendor_id);
279                     break;
280           }
281 
282           return tuner_type;
283 }
284