xref: /dflybsd-src/sys/dev/video/cxm/cxm_eeprom.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /*
286d7f5d3SJohn Marino  * Copyright (c) 2003, 2004, 2005
386d7f5d3SJohn Marino  *	John Wehle <john@feith.com>.  All rights reserved.
486d7f5d3SJohn Marino  *
586d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
686d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions
786d7f5d3SJohn Marino  * are met:
886d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
986d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
1086d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
1186d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
1286d7f5d3SJohn Marino  *    documentation and/or other materials provided with the distribution.
1386d7f5d3SJohn Marino  * 3. All advertising materials mentioning features or use of this software
1486d7f5d3SJohn Marino  *    must display the following acknowledgement:
1586d7f5d3SJohn Marino  *	This product includes software developed by John Wehle.
1686d7f5d3SJohn Marino  * 4. The name of the author may not be used to endorse or promote products
1786d7f5d3SJohn Marino  *    derived from this software without specific prior written permission.
1886d7f5d3SJohn Marino  *
1986d7f5d3SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2086d7f5d3SJohn Marino  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2186d7f5d3SJohn Marino  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2286d7f5d3SJohn Marino  * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2386d7f5d3SJohn Marino  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2486d7f5d3SJohn Marino  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2586d7f5d3SJohn Marino  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2686d7f5d3SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2786d7f5d3SJohn Marino  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2886d7f5d3SJohn Marino  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2986d7f5d3SJohn Marino  * POSSIBILITY OF SUCH DAMAGE.
3086d7f5d3SJohn Marino  */
3186d7f5d3SJohn Marino 
3286d7f5d3SJohn Marino /*
3386d7f5d3SJohn Marino  * EEPROM routines for the Conexant MPEG-2 Codec driver.
3486d7f5d3SJohn Marino  *
3586d7f5d3SJohn Marino  * Ideally these routines should be implemented as a separate
3686d7f5d3SJohn Marino  * driver which has a generic EEPROM interface so that it's
3786d7f5d3SJohn Marino  * not necessary for each multimedia driver to re-invent the
3886d7f5d3SJohn Marino  * wheel.
3986d7f5d3SJohn Marino  */
4086d7f5d3SJohn Marino 
4186d7f5d3SJohn Marino 
4286d7f5d3SJohn Marino #include <sys/param.h>
4386d7f5d3SJohn Marino #include <sys/systm.h>
4486d7f5d3SJohn Marino #include <sys/conf.h>
4586d7f5d3SJohn Marino #include <sys/uio.h>
4686d7f5d3SJohn Marino #include <sys/kernel.h>
4786d7f5d3SJohn Marino #include <sys/poll.h>
4886d7f5d3SJohn Marino #include <sys/select.h>
4986d7f5d3SJohn Marino #include <sys/resource.h>
5086d7f5d3SJohn Marino #include <sys/bus.h>
5186d7f5d3SJohn Marino #include <sys/rman.h>
5286d7f5d3SJohn Marino 
5386d7f5d3SJohn Marino 
5486d7f5d3SJohn Marino #include <machine/clock.h>
5586d7f5d3SJohn Marino 
5686d7f5d3SJohn Marino #include <dev/video/cxm/cxm.h>
5786d7f5d3SJohn Marino 
5886d7f5d3SJohn Marino #include <bus/iicbus/iiconf.h>
5986d7f5d3SJohn Marino #include <bus/iicbus/iicbus.h>
6086d7f5d3SJohn Marino 
6186d7f5d3SJohn Marino #include "iicbb_if.h"
6286d7f5d3SJohn Marino 
6386d7f5d3SJohn Marino 
6486d7f5d3SJohn Marino static int
cxm_eeprom_read(device_t iicbus,int i2c_addr,char * buf,int len,unsigned int offset)6586d7f5d3SJohn Marino cxm_eeprom_read(device_t iicbus, int i2c_addr,
6686d7f5d3SJohn Marino 		 char *buf, int len, unsigned int offset)
6786d7f5d3SJohn Marino {
6886d7f5d3SJohn Marino 	char msg[1];
6986d7f5d3SJohn Marino 	int received;
7086d7f5d3SJohn Marino 	int sent;
7186d7f5d3SJohn Marino 
7286d7f5d3SJohn Marino 	msg[0] = (unsigned char)offset;
7386d7f5d3SJohn Marino 
7486d7f5d3SJohn Marino 	if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
7586d7f5d3SJohn Marino 		return -1;
7686d7f5d3SJohn Marino 
7786d7f5d3SJohn Marino 	if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
7886d7f5d3SJohn Marino 	    || sent != sizeof(msg))
7986d7f5d3SJohn Marino 		goto fail;
8086d7f5d3SJohn Marino 
8186d7f5d3SJohn Marino 	if (iicbus_repeated_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0)
8286d7f5d3SJohn Marino 		goto fail;
8386d7f5d3SJohn Marino 
8486d7f5d3SJohn Marino 	if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0)
8586d7f5d3SJohn Marino 		goto fail;
8686d7f5d3SJohn Marino 
8786d7f5d3SJohn Marino 	iicbus_stop(iicbus);
8886d7f5d3SJohn Marino 
8986d7f5d3SJohn Marino         return received;
9086d7f5d3SJohn Marino 
9186d7f5d3SJohn Marino fail:
9286d7f5d3SJohn Marino 	iicbus_stop(iicbus);
9386d7f5d3SJohn Marino 	return -1;
9486d7f5d3SJohn Marino }
9586d7f5d3SJohn Marino 
9686d7f5d3SJohn Marino 
9786d7f5d3SJohn Marino int
cxm_eeprom_init(struct cxm_softc * sc)9886d7f5d3SJohn Marino cxm_eeprom_init(struct cxm_softc *sc)
9986d7f5d3SJohn Marino {
10086d7f5d3SJohn Marino 	unsigned char eeprom[1];
10186d7f5d3SJohn Marino 
10286d7f5d3SJohn Marino 	if (cxm_eeprom_read(sc->iicbus, CXM_I2C_EEPROM,
10386d7f5d3SJohn Marino 			    eeprom, sizeof(eeprom), 0) != sizeof(eeprom))
10486d7f5d3SJohn Marino 		return -1;
10586d7f5d3SJohn Marino 
10686d7f5d3SJohn Marino 	return 0;
10786d7f5d3SJohn Marino }
10886d7f5d3SJohn Marino 
10986d7f5d3SJohn Marino 
11086d7f5d3SJohn Marino int
cxm_eeprom_tuner_type(struct cxm_softc * sc)11186d7f5d3SJohn Marino cxm_eeprom_tuner_type(struct cxm_softc *sc)
11286d7f5d3SJohn Marino {
11386d7f5d3SJohn Marino 	unsigned char eeprom[256];
11486d7f5d3SJohn Marino 	unsigned int i;
11586d7f5d3SJohn Marino 	unsigned int len;
11686d7f5d3SJohn Marino 	unsigned int subsystem_vendor_id;
11786d7f5d3SJohn Marino 	unsigned int tuner_code;
11886d7f5d3SJohn Marino 	int tuner_type;
11986d7f5d3SJohn Marino 
12086d7f5d3SJohn Marino 	if (cxm_eeprom_read(sc->iicbus, CXM_I2C_EEPROM,
12186d7f5d3SJohn Marino 			    eeprom, sizeof(eeprom), 0) != sizeof(eeprom))
12286d7f5d3SJohn Marino 		return -1;
12386d7f5d3SJohn Marino 
12486d7f5d3SJohn Marino 	subsystem_vendor_id = (unsigned int)eeprom[254] << 8 | eeprom[255];
12586d7f5d3SJohn Marino 	tuner_type = -1;
12686d7f5d3SJohn Marino 
12786d7f5d3SJohn Marino 	switch (subsystem_vendor_id) {
12886d7f5d3SJohn Marino 	case PCI_VENDOR_HAUPPAUGE:
12986d7f5d3SJohn Marino 
13086d7f5d3SJohn Marino 		/*
13186d7f5d3SJohn Marino 		 * The Hauppauge eeprom format is tagged.
13286d7f5d3SJohn Marino 		 */
13386d7f5d3SJohn Marino 
13486d7f5d3SJohn Marino 		if (eeprom[0] != 0x84) {
13586d7f5d3SJohn Marino 			device_printf(sc->dev,
13686d7f5d3SJohn Marino 			    "unknown Hauppauge eeprom format %#x\n",
13786d7f5d3SJohn Marino 			    (unsigned int)eeprom[0]);
13886d7f5d3SJohn Marino 			break;
13986d7f5d3SJohn Marino 		}
14086d7f5d3SJohn Marino 
14186d7f5d3SJohn Marino 		tuner_code = -1;
14286d7f5d3SJohn Marino 
14386d7f5d3SJohn Marino 		for (i = 0; i < sizeof(eeprom); i += len) {
14486d7f5d3SJohn Marino 			len = 0;
14586d7f5d3SJohn Marino 			if (eeprom[i] == 0x84) {
14686d7f5d3SJohn Marino 				len = (unsigned int)eeprom[i + 2] << 8
14786d7f5d3SJohn Marino 				      | eeprom[i + 1];
14886d7f5d3SJohn Marino 				i += 3;
14986d7f5d3SJohn Marino 			} else if ((eeprom[i] & 0xf0) == 0x70) {
15086d7f5d3SJohn Marino 				if (eeprom[i] & 0x08)
15186d7f5d3SJohn Marino 					break;
15286d7f5d3SJohn Marino 				len = eeprom[i] & 0x07;
15386d7f5d3SJohn Marino 				i++;
15486d7f5d3SJohn Marino 			} else {
15586d7f5d3SJohn Marino 				device_printf(sc->dev,
15686d7f5d3SJohn Marino 				    "unknown Hauppauge eeprom packet %#x\n",
15786d7f5d3SJohn Marino 				    (unsigned int)eeprom[i]);
15886d7f5d3SJohn Marino 				return -1;
15986d7f5d3SJohn Marino 			}
16086d7f5d3SJohn Marino 
16186d7f5d3SJohn Marino 			if (i >= sizeof(eeprom)
16286d7f5d3SJohn Marino 			    || (i + len) > sizeof(eeprom)) {
16386d7f5d3SJohn Marino 				device_printf(sc->dev,
16486d7f5d3SJohn Marino 				    "corrupt Hauppauge eeprom packet\n");
16586d7f5d3SJohn Marino 				return -1;
16686d7f5d3SJohn Marino 			}
16786d7f5d3SJohn Marino 
16886d7f5d3SJohn Marino 			switch (eeprom[i]) {
16986d7f5d3SJohn Marino 			case 0x00:
17086d7f5d3SJohn Marino 				tuner_code = eeprom[i + 6];
17186d7f5d3SJohn Marino 				break;
17286d7f5d3SJohn Marino 
17386d7f5d3SJohn Marino 			case 0x0a:
17486d7f5d3SJohn Marino 				tuner_code = eeprom[i + 2];
17586d7f5d3SJohn Marino 				break;
17686d7f5d3SJohn Marino 
17786d7f5d3SJohn Marino 			default:
17886d7f5d3SJohn Marino 				break;
17986d7f5d3SJohn Marino 			}
18086d7f5d3SJohn Marino 		}
18186d7f5d3SJohn Marino 
18286d7f5d3SJohn Marino 		switch (tuner_code) {
18386d7f5d3SJohn Marino 		case 0x03: /* Philips FI1216 */
18486d7f5d3SJohn Marino 		case 0x08: /* Philips FI1216 MK2 */
18586d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_PHILIPS_FI1216_MK2;
18686d7f5d3SJohn Marino 			break;
18786d7f5d3SJohn Marino 
18886d7f5d3SJohn Marino 		case 0x22: /* Philips FQ1216ME */
18986d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_PHILIPS_FQ1216ME;
19086d7f5d3SJohn Marino 			break;
19186d7f5d3SJohn Marino 
19286d7f5d3SJohn Marino 		case 0x37: /* Philips FQ1216ME MK3 */
19386d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_PHILIPS_FQ1216ME_MK3;
19486d7f5d3SJohn Marino 			break;
19586d7f5d3SJohn Marino 
19686d7f5d3SJohn Marino 		case 0x1d: /* Temic 4006FH5 */
19786d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_TEMIC_4006_FH5;
19886d7f5d3SJohn Marino 			break;
19986d7f5d3SJohn Marino 
20086d7f5d3SJohn Marino 		case 0x30: /* LG Innotek TPI8PSB11D */
20186d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_LG_TPI8PSB11D;
20286d7f5d3SJohn Marino 			break;
20386d7f5d3SJohn Marino 
20486d7f5d3SJohn Marino 		case 0x34: /* Microtune 4049FM5 */
20586d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_MICROTUNE_4049_FM5;
20686d7f5d3SJohn Marino 			break;
20786d7f5d3SJohn Marino 
20886d7f5d3SJohn Marino 		case 0x05: /* Philips FI1236 */
20986d7f5d3SJohn Marino 		case 0x0a: /* Philips FI1236 MK2 */
21086d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_PHILIPS_FI1236_MK2;
21186d7f5d3SJohn Marino 			break;
21286d7f5d3SJohn Marino 
21386d7f5d3SJohn Marino 		case 0x1a: /* Temic 4036FY5 */
21486d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_TEMIC_4036_FY5;
21586d7f5d3SJohn Marino 			break;
21686d7f5d3SJohn Marino 
21786d7f5d3SJohn Marino 		case 0x52: /* LG Innotek TAPC-H701F */
21886d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_LG_TAPC_H701F;
21986d7f5d3SJohn Marino 			break;
22086d7f5d3SJohn Marino 
22186d7f5d3SJohn Marino 		case 0x55: /* TCL 2002N-6A */
22286d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_TCL_2002N_6A;
22386d7f5d3SJohn Marino 			break;
22486d7f5d3SJohn Marino 
22586d7f5d3SJohn Marino 		case 0x06: /* Philips FI1246 */
22686d7f5d3SJohn Marino 		case 0x0b: /* Philips FI1246 MK2 */
22786d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_PHILIPS_FI1246_MK2;
22886d7f5d3SJohn Marino 			break;
22986d7f5d3SJohn Marino 
23086d7f5d3SJohn Marino 		case 0x23: /* Temic 4066FY5 */
23186d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_TEMIC_4066_FY5;
23286d7f5d3SJohn Marino 			break;
23386d7f5d3SJohn Marino 
23486d7f5d3SJohn Marino 		case 0x10: /* Philips FR1216 MK2 */
23586d7f5d3SJohn Marino 		case 0x15: /* Philips FM1216 */
23686d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_PHILIPS_FM1216;
23786d7f5d3SJohn Marino 			break;
23886d7f5d3SJohn Marino 
23986d7f5d3SJohn Marino 		case 0x39: /* Philips FM1216ME MK3 */
24086d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_PHILIPS_FM1216ME_MK3;
24186d7f5d3SJohn Marino 			break;
24286d7f5d3SJohn Marino 
24386d7f5d3SJohn Marino 		case 0x2a: /* Temic 4009FR5 */
24486d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_TEMIC_4009_FR5;
24586d7f5d3SJohn Marino 			break;
24686d7f5d3SJohn Marino 
24786d7f5d3SJohn Marino 		case 0x2f: /* LG Innotek TPI8PSB01N */
24886d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_LG_TPI8PSB01N;
24986d7f5d3SJohn Marino 			break;
25086d7f5d3SJohn Marino 
25186d7f5d3SJohn Marino 		case 0x12: /* Philips FR1236 MK2 */
25286d7f5d3SJohn Marino 		case 0x17: /* Philips FM1236 */
25386d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_PHILIPS_FM1236;
25486d7f5d3SJohn Marino 			break;
25586d7f5d3SJohn Marino 
25686d7f5d3SJohn Marino 		case 0x21: /* Temic 4039FR5 */
25786d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_TEMIC_4039_FR5;
25886d7f5d3SJohn Marino 			break;
25986d7f5d3SJohn Marino 
26086d7f5d3SJohn Marino 		case 0x44: /* LG Innotek TAPE-H001F */
26186d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_LG_TAPE_H001F;
26286d7f5d3SJohn Marino 			break;
26386d7f5d3SJohn Marino 
26486d7f5d3SJohn Marino 		case 0x13: /* Philips FR1246 MK2 */
26586d7f5d3SJohn Marino 		case 0x18: /* Philips FM1246 */
26686d7f5d3SJohn Marino 			tuner_type = CXM_TUNER_PHILIPS_FM1246;
26786d7f5d3SJohn Marino 			break;
26886d7f5d3SJohn Marino 
26986d7f5d3SJohn Marino 		default:
27086d7f5d3SJohn Marino 			device_printf(sc->dev, "unknown tuner code %#x\n",
27186d7f5d3SJohn Marino 			    tuner_code);
27286d7f5d3SJohn Marino 			break;
27386d7f5d3SJohn Marino 		}
27486d7f5d3SJohn Marino 		break;
27586d7f5d3SJohn Marino 
27686d7f5d3SJohn Marino 	default:
27786d7f5d3SJohn Marino 		device_printf(sc->dev, "unknown subsystem vendor id %#x\n",
27886d7f5d3SJohn Marino 		    subsystem_vendor_id);
27986d7f5d3SJohn Marino 		break;
28086d7f5d3SJohn Marino 	}
28186d7f5d3SJohn Marino 
28286d7f5d3SJohn Marino 	return tuner_type;
28386d7f5d3SJohn Marino }
284