diff options
Diffstat (limited to 'drivers/media/dvb/frontends/dibx000_common.c')
-rw-r--r-- | drivers/media/dvb/frontends/dibx000_common.c | 95 |
1 files changed, 61 insertions, 34 deletions
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index 315e09e95b0c..4efca30d2127 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c | |||
@@ -15,29 +15,31 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) | |||
15 | (val >> 8) & 0xff, val & 0xff, | 15 | (val >> 8) & 0xff, val & 0xff, |
16 | }; | 16 | }; |
17 | struct i2c_msg msg = { | 17 | struct i2c_msg msg = { |
18 | .addr = mst->i2c_addr, .flags = 0, .buf = b, .len = 4 | 18 | .addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4 |
19 | }; | 19 | }; |
20 | return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; | 20 | return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; |
21 | } | 21 | } |
22 | 22 | ||
23 | 23 | ||
24 | static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf) | 24 | static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, |
25 | enum dibx000_i2c_interface intf) | ||
25 | { | 26 | { |
26 | if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { | 27 | if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { |
27 | dprintk("selecting interface: %d\n",intf); | 28 | dprintk("selecting interface: %d\n", intf); |
28 | mst->selected_interface = intf; | 29 | mst->selected_interface = intf; |
29 | return dibx000_write_word(mst, mst->base_reg + 4, intf); | 30 | return dibx000_write_word(mst, mst->base_reg + 4, intf); |
30 | } | 31 | } |
31 | return 0; | 32 | return 0; |
32 | } | 33 | } |
33 | 34 | ||
34 | static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], u8 addr, int onoff) | 35 | static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], |
36 | u8 addr, int onoff) | ||
35 | { | 37 | { |
36 | u16 val; | 38 | u16 val; |
37 | 39 | ||
38 | 40 | ||
39 | if (onoff) | 41 | if (onoff) |
40 | val = addr << 8; // bit 7 = use master or not, if 0, the gate is open | 42 | val = addr << 8; // bit 7 = use master or not, if 0, the gate is open |
41 | else | 43 | else |
42 | val = 1 << 7; | 44 | val = 1 << 7; |
43 | 45 | ||
@@ -45,7 +47,7 @@ static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], u8 ad | |||
45 | val <<= 1; | 47 | val <<= 1; |
46 | 48 | ||
47 | tx[0] = (((mst->base_reg + 1) >> 8) & 0xff); | 49 | tx[0] = (((mst->base_reg + 1) >> 8) & 0xff); |
48 | tx[1] = ( (mst->base_reg + 1) & 0xff); | 50 | tx[1] = ((mst->base_reg + 1) & 0xff); |
49 | tx[2] = val >> 8; | 51 | tx[2] = val >> 8; |
50 | tx[3] = val & 0xff; | 52 | tx[3] = val & 0xff; |
51 | 53 | ||
@@ -57,59 +59,78 @@ static u32 dibx000_i2c_func(struct i2c_adapter *adapter) | |||
57 | return I2C_FUNC_I2C; | 59 | return I2C_FUNC_I2C; |
58 | } | 60 | } |
59 | 61 | ||
60 | static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) | 62 | static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, |
63 | struct i2c_msg msg[], int num) | ||
61 | { | 64 | { |
62 | struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); | 65 | struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); |
63 | struct i2c_msg m[2 + num]; | 66 | struct i2c_msg m[2 + num]; |
64 | u8 tx_open[4], tx_close[4]; | 67 | u8 tx_open[4], tx_close[4]; |
65 | 68 | ||
66 | memset(m,0, sizeof(struct i2c_msg) * (2 + num)); | 69 | memset(m, 0, sizeof(struct i2c_msg) * (2 + num)); |
67 | 70 | ||
68 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); | 71 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); |
69 | 72 | ||
70 | dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1); | 73 | dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1); |
71 | m[0].addr = mst->i2c_addr; | 74 | m[0].addr = mst->i2c_addr; |
72 | m[0].buf = tx_open; | 75 | m[0].buf = tx_open; |
73 | m[0].len = 4; | 76 | m[0].len = 4; |
74 | 77 | ||
75 | memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); | 78 | memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); |
76 | 79 | ||
77 | dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0); | 80 | dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0); |
78 | m[num+1].addr = mst->i2c_addr; | 81 | m[num + 1].addr = mst->i2c_addr; |
79 | m[num+1].buf = tx_close; | 82 | m[num + 1].buf = tx_close; |
80 | m[num+1].len = 4; | 83 | m[num + 1].len = 4; |
81 | 84 | ||
82 | return i2c_transfer(mst->i2c_adap, m, 2+num) == 2 + num ? num : -EIO; | 85 | return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO; |
83 | } | 86 | } |
84 | 87 | ||
85 | static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { | 88 | static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { |
86 | .master_xfer = dibx000_i2c_gated_tuner_xfer, | 89 | .master_xfer = dibx000_i2c_gated_tuner_xfer, |
87 | .functionality = dibx000_i2c_func, | 90 | .functionality = dibx000_i2c_func, |
88 | }; | 91 | }; |
89 | 92 | ||
90 | struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating) | 93 | struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, |
94 | enum dibx000_i2c_interface intf, | ||
95 | int gating) | ||
91 | { | 96 | { |
92 | struct i2c_adapter *i2c = NULL; | 97 | struct i2c_adapter *i2c = NULL; |
93 | 98 | ||
94 | switch (intf) { | 99 | switch (intf) { |
95 | case DIBX000_I2C_INTERFACE_TUNER: | 100 | case DIBX000_I2C_INTERFACE_TUNER: |
96 | if (gating) | 101 | if (gating) |
97 | i2c = &mst->gated_tuner_i2c_adap; | 102 | i2c = &mst->gated_tuner_i2c_adap; |
98 | break; | 103 | break; |
99 | default: | 104 | default: |
100 | printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n"); | 105 | printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n"); |
101 | break; | 106 | break; |
102 | } | 107 | } |
103 | 108 | ||
104 | return i2c; | 109 | return i2c; |
105 | } | 110 | } |
111 | |||
106 | EXPORT_SYMBOL(dibx000_get_i2c_adapter); | 112 | EXPORT_SYMBOL(dibx000_get_i2c_adapter); |
107 | 113 | ||
108 | static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst) | 114 | void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst) |
115 | { | ||
116 | /* initialize the i2c-master by closing the gate */ | ||
117 | u8 tx[4]; | ||
118 | struct i2c_msg m = {.addr = mst->i2c_addr,.buf = tx,.len = 4 }; | ||
119 | |||
120 | dibx000_i2c_gate_ctrl(mst, tx, 0, 0); | ||
121 | i2c_transfer(mst->i2c_adap, &m, 1); | ||
122 | mst->selected_interface = 0xff; // the first time force a select of the I2C | ||
123 | dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); | ||
124 | } | ||
125 | |||
126 | EXPORT_SYMBOL(dibx000_reset_i2c_master); | ||
127 | |||
128 | static int i2c_adapter_init(struct i2c_adapter *i2c_adap, | ||
129 | struct i2c_algorithm *algo, const char *name, | ||
130 | struct dibx000_i2c_master *mst) | ||
109 | { | 131 | { |
110 | strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); | 132 | strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); |
111 | i2c_adap->class = I2C_CLASS_TV_DIGITAL, | 133 | i2c_adap->class = I2C_CLASS_TV_DIGITAL, i2c_adap->algo = algo; |
112 | i2c_adap->algo = algo; | ||
113 | i2c_adap->algo_data = NULL; | 134 | i2c_adap->algo_data = NULL; |
114 | i2c_set_adapdata(i2c_adap, mst); | 135 | i2c_set_adapdata(i2c_adap, mst); |
115 | if (i2c_add_adapter(i2c_adap) < 0) | 136 | if (i2c_add_adapter(i2c_adap) < 0) |
@@ -117,34 +138,40 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm * | |||
117 | return 0; | 138 | return 0; |
118 | } | 139 | } |
119 | 140 | ||
120 | int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr) | 141 | int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, |
142 | struct i2c_adapter *i2c_adap, u8 i2c_addr) | ||
121 | { | 143 | { |
122 | u8 tx[4]; | 144 | u8 tx[4]; |
123 | struct i2c_msg m = { .addr = i2c_addr >> 1, .buf = tx, .len = 4 }; | 145 | struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 }; |
124 | 146 | ||
125 | mst->device_rev = device_rev; | 147 | mst->device_rev = device_rev; |
126 | mst->i2c_adap = i2c_adap; | 148 | mst->i2c_adap = i2c_adap; |
127 | mst->i2c_addr = i2c_addr >> 1; | 149 | mst->i2c_addr = i2c_addr >> 1; |
128 | 150 | ||
129 | if (device_rev == DIB7000P) | 151 | if (device_rev == DIB7000P || device_rev == DIB8000) |
130 | mst->base_reg = 1024; | 152 | mst->base_reg = 1024; |
131 | else | 153 | else |
132 | mst->base_reg = 768; | 154 | mst->base_reg = 768; |
133 | 155 | ||
134 | if (i2c_adapter_init(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, "DiBX000 tuner I2C bus", mst) != 0) | 156 | if (i2c_adapter_init |
135 | printk(KERN_ERR "DiBX000: could not initialize the tuner i2c_adapter\n"); | 157 | (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, |
158 | "DiBX000 tuner I2C bus", mst) != 0) | ||
159 | printk(KERN_ERR | ||
160 | "DiBX000: could not initialize the tuner i2c_adapter\n"); | ||
136 | 161 | ||
137 | /* initialize the i2c-master by closing the gate */ | 162 | /* initialize the i2c-master by closing the gate */ |
138 | dibx000_i2c_gate_ctrl(mst, tx, 0, 0); | 163 | dibx000_i2c_gate_ctrl(mst, tx, 0, 0); |
139 | 164 | ||
140 | return i2c_transfer(i2c_adap, &m, 1) == 1; | 165 | return i2c_transfer(i2c_adap, &m, 1) == 1; |
141 | } | 166 | } |
167 | |||
142 | EXPORT_SYMBOL(dibx000_init_i2c_master); | 168 | EXPORT_SYMBOL(dibx000_init_i2c_master); |
143 | 169 | ||
144 | void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) | 170 | void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) |
145 | { | 171 | { |
146 | i2c_del_adapter(&mst->gated_tuner_i2c_adap); | 172 | i2c_del_adapter(&mst->gated_tuner_i2c_adap); |
147 | } | 173 | } |
174 | |||
148 | EXPORT_SYMBOL(dibx000_exit_i2c_master); | 175 | EXPORT_SYMBOL(dibx000_exit_i2c_master); |
149 | 176 | ||
150 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); | 177 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); |