1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2005 Mike Isely <isely@pobox.com>
5*4882a593Smuzhiyun * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/slab.h>
9*4882a593Smuzhiyun #include "pvrusb2-eeprom.h"
10*4882a593Smuzhiyun #include "pvrusb2-hdw-internal.h"
11*4882a593Smuzhiyun #include "pvrusb2-debug.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__)
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun /*
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun Read and analyze data in the eeprom. Use tveeprom to figure out
20*4882a593Smuzhiyun the packet structure, since this is another Hauppauge device and
21*4882a593Smuzhiyun internally it has a family resemblance to ivtv-type devices
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun */
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include <media/tveeprom.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /* We seem to only be interested in the last 128 bytes of the EEPROM */
28*4882a593Smuzhiyun #define EEPROM_SIZE 128
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /* Grab EEPROM contents, needed for direct method. */
pvr2_eeprom_fetch(struct pvr2_hdw * hdw)31*4882a593Smuzhiyun static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun struct i2c_msg msg[2];
34*4882a593Smuzhiyun u8 *eeprom;
35*4882a593Smuzhiyun u8 iadd[2];
36*4882a593Smuzhiyun u8 addr;
37*4882a593Smuzhiyun u16 eepromSize;
38*4882a593Smuzhiyun unsigned int offs;
39*4882a593Smuzhiyun int ret;
40*4882a593Smuzhiyun int mode16 = 0;
41*4882a593Smuzhiyun unsigned pcnt,tcnt;
42*4882a593Smuzhiyun eeprom = kzalloc(EEPROM_SIZE, GFP_KERNEL);
43*4882a593Smuzhiyun if (!eeprom) {
44*4882a593Smuzhiyun pvr2_trace(PVR2_TRACE_ERROR_LEGS,
45*4882a593Smuzhiyun "Failed to allocate memory required to read eeprom");
46*4882a593Smuzhiyun return NULL;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun trace_eeprom("Value for eeprom addr from controller was 0x%x",
50*4882a593Smuzhiyun hdw->eeprom_addr);
51*4882a593Smuzhiyun addr = hdw->eeprom_addr;
52*4882a593Smuzhiyun /* Seems that if the high bit is set, then the *real* eeprom
53*4882a593Smuzhiyun address is shifted right now bit position (noticed this in
54*4882a593Smuzhiyun newer PVR USB2 hardware) */
55*4882a593Smuzhiyun if (addr & 0x80) addr >>= 1;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* FX2 documentation states that a 16bit-addressed eeprom is
58*4882a593Smuzhiyun expected if the I2C address is an odd number (yeah, this is
59*4882a593Smuzhiyun strange but it's what they do) */
60*4882a593Smuzhiyun mode16 = (addr & 1);
61*4882a593Smuzhiyun eepromSize = (mode16 ? 4096 : 256);
62*4882a593Smuzhiyun trace_eeprom("Examining %d byte eeprom at location 0x%x using %d bit addressing",
63*4882a593Smuzhiyun eepromSize, addr,
64*4882a593Smuzhiyun mode16 ? 16 : 8);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun msg[0].addr = addr;
67*4882a593Smuzhiyun msg[0].flags = 0;
68*4882a593Smuzhiyun msg[0].len = mode16 ? 2 : 1;
69*4882a593Smuzhiyun msg[0].buf = iadd;
70*4882a593Smuzhiyun msg[1].addr = addr;
71*4882a593Smuzhiyun msg[1].flags = I2C_M_RD;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* We have to do the actual eeprom data fetch ourselves, because
74*4882a593Smuzhiyun (1) we're only fetching part of the eeprom, and (2) if we were
75*4882a593Smuzhiyun getting the whole thing our I2C driver can't grab it in one
76*4882a593Smuzhiyun pass - which is what tveeprom is otherwise going to attempt */
77*4882a593Smuzhiyun for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) {
78*4882a593Smuzhiyun pcnt = 16;
79*4882a593Smuzhiyun if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt;
80*4882a593Smuzhiyun offs = tcnt + (eepromSize - EEPROM_SIZE);
81*4882a593Smuzhiyun if (mode16) {
82*4882a593Smuzhiyun iadd[0] = offs >> 8;
83*4882a593Smuzhiyun iadd[1] = offs;
84*4882a593Smuzhiyun } else {
85*4882a593Smuzhiyun iadd[0] = offs;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun msg[1].len = pcnt;
88*4882a593Smuzhiyun msg[1].buf = eeprom+tcnt;
89*4882a593Smuzhiyun if ((ret = i2c_transfer(&hdw->i2c_adap,
90*4882a593Smuzhiyun msg,ARRAY_SIZE(msg))) != 2) {
91*4882a593Smuzhiyun pvr2_trace(PVR2_TRACE_ERROR_LEGS,
92*4882a593Smuzhiyun "eeprom fetch set offs err=%d",ret);
93*4882a593Smuzhiyun kfree(eeprom);
94*4882a593Smuzhiyun return NULL;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun return eeprom;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* Directly call eeprom analysis function within tveeprom. */
pvr2_eeprom_analyze(struct pvr2_hdw * hdw)102*4882a593Smuzhiyun int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun u8 *eeprom;
105*4882a593Smuzhiyun struct tveeprom tvdata;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun memset(&tvdata,0,sizeof(tvdata));
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun eeprom = pvr2_eeprom_fetch(hdw);
110*4882a593Smuzhiyun if (!eeprom)
111*4882a593Smuzhiyun return -EINVAL;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun tveeprom_hauppauge_analog(&tvdata, eeprom);
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun trace_eeprom("eeprom assumed v4l tveeprom module");
116*4882a593Smuzhiyun trace_eeprom("eeprom direct call results:");
117*4882a593Smuzhiyun trace_eeprom("has_radio=%d",tvdata.has_radio);
118*4882a593Smuzhiyun trace_eeprom("tuner_type=%d",tvdata.tuner_type);
119*4882a593Smuzhiyun trace_eeprom("tuner_formats=0x%x",tvdata.tuner_formats);
120*4882a593Smuzhiyun trace_eeprom("audio_processor=%d",tvdata.audio_processor);
121*4882a593Smuzhiyun trace_eeprom("model=%d",tvdata.model);
122*4882a593Smuzhiyun trace_eeprom("revision=%d",tvdata.revision);
123*4882a593Smuzhiyun trace_eeprom("serial_number=%d",tvdata.serial_number);
124*4882a593Smuzhiyun trace_eeprom("rev_str=%s",tvdata.rev_str);
125*4882a593Smuzhiyun hdw->tuner_type = tvdata.tuner_type;
126*4882a593Smuzhiyun hdw->tuner_updated = !0;
127*4882a593Smuzhiyun hdw->serial_number = tvdata.serial_number;
128*4882a593Smuzhiyun hdw->std_mask_eeprom = tvdata.tuner_formats;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun kfree(eeprom);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun return 0;
133*4882a593Smuzhiyun }
134