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