1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * cb710/mmc.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright by Michał Mirosław, 2008-2009
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include <linux/kernel.h>
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/pci.h>
10*4882a593Smuzhiyun #include <linux/delay.h>
11*4882a593Smuzhiyun #include "cb710-mmc.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #define CB710_MMC_REQ_TIMEOUT_MS 2000
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun static const u8 cb710_clock_divider_log2[8] = {
16*4882a593Smuzhiyun /* 1, 2, 4, 8, 16, 32, 128, 512 */
17*4882a593Smuzhiyun 0, 1, 2, 3, 4, 5, 7, 9
18*4882a593Smuzhiyun };
19*4882a593Smuzhiyun #define CB710_MAX_DIVIDER_IDX \
20*4882a593Smuzhiyun (ARRAY_SIZE(cb710_clock_divider_log2) - 1)
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static const u8 cb710_src_freq_mhz[16] = {
23*4882a593Smuzhiyun 33, 10, 20, 25, 30, 35, 40, 45,
24*4882a593Smuzhiyun 50, 55, 60, 65, 70, 75, 80, 85
25*4882a593Smuzhiyun };
26*4882a593Smuzhiyun
cb710_mmc_select_clock_divider(struct mmc_host * mmc,int hz)27*4882a593Smuzhiyun static void cb710_mmc_select_clock_divider(struct mmc_host *mmc, int hz)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
30*4882a593Smuzhiyun struct pci_dev *pdev = cb710_slot_to_chip(slot)->pdev;
31*4882a593Smuzhiyun u32 src_freq_idx;
32*4882a593Smuzhiyun u32 divider_idx;
33*4882a593Smuzhiyun int src_hz;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* on CB710 in HP nx9500:
36*4882a593Smuzhiyun * src_freq_idx == 0
37*4882a593Smuzhiyun * indexes 1-7 work as written in the table
38*4882a593Smuzhiyun * indexes 0,8-15 give no clock output
39*4882a593Smuzhiyun */
40*4882a593Smuzhiyun pci_read_config_dword(pdev, 0x48, &src_freq_idx);
41*4882a593Smuzhiyun src_freq_idx = (src_freq_idx >> 16) & 0xF;
42*4882a593Smuzhiyun src_hz = cb710_src_freq_mhz[src_freq_idx] * 1000000;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun for (divider_idx = 0; divider_idx < CB710_MAX_DIVIDER_IDX; ++divider_idx) {
45*4882a593Smuzhiyun if (hz >= src_hz >> cb710_clock_divider_log2[divider_idx])
46*4882a593Smuzhiyun break;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun if (src_freq_idx)
50*4882a593Smuzhiyun divider_idx |= 0x8;
51*4882a593Smuzhiyun else if (divider_idx == 0)
52*4882a593Smuzhiyun divider_idx = 1;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun cb710_pci_update_config_reg(pdev, 0x40, ~0xF0000000, divider_idx << 28);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot),
57*4882a593Smuzhiyun "clock set to %d Hz, wanted %d Hz; src_freq_idx = %d, divider_idx = %d|%d\n",
58*4882a593Smuzhiyun src_hz >> cb710_clock_divider_log2[divider_idx & 7],
59*4882a593Smuzhiyun hz, src_freq_idx, divider_idx & 7, divider_idx & 8);
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
__cb710_mmc_enable_irq(struct cb710_slot * slot,unsigned short enable,unsigned short mask)62*4882a593Smuzhiyun static void __cb710_mmc_enable_irq(struct cb710_slot *slot,
63*4882a593Smuzhiyun unsigned short enable, unsigned short mask)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun /* clear global IE
66*4882a593Smuzhiyun * - it gets set later if any interrupt sources are enabled */
67*4882a593Smuzhiyun mask |= CB710_MMC_IE_IRQ_ENABLE;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* look like interrupt is fired whenever
70*4882a593Smuzhiyun * WORD[0x0C] & WORD[0x10] != 0;
71*4882a593Smuzhiyun * -> bit 15 port 0x0C seems to be global interrupt enable
72*4882a593Smuzhiyun */
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun enable = (cb710_read_port_16(slot, CB710_MMC_IRQ_ENABLE_PORT)
75*4882a593Smuzhiyun & ~mask) | enable;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (enable)
78*4882a593Smuzhiyun enable |= CB710_MMC_IE_IRQ_ENABLE;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun cb710_write_port_16(slot, CB710_MMC_IRQ_ENABLE_PORT, enable);
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
cb710_mmc_enable_irq(struct cb710_slot * slot,unsigned short enable,unsigned short mask)83*4882a593Smuzhiyun static void cb710_mmc_enable_irq(struct cb710_slot *slot,
84*4882a593Smuzhiyun unsigned short enable, unsigned short mask)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun struct cb710_mmc_reader *reader = mmc_priv(cb710_slot_to_mmc(slot));
87*4882a593Smuzhiyun unsigned long flags;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun spin_lock_irqsave(&reader->irq_lock, flags);
90*4882a593Smuzhiyun /* this is the only thing irq_lock protects */
91*4882a593Smuzhiyun __cb710_mmc_enable_irq(slot, enable, mask);
92*4882a593Smuzhiyun spin_unlock_irqrestore(&reader->irq_lock, flags);
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
cb710_mmc_reset_events(struct cb710_slot * slot)95*4882a593Smuzhiyun static void cb710_mmc_reset_events(struct cb710_slot *slot)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, 0xFF);
98*4882a593Smuzhiyun cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, 0xFF);
99*4882a593Smuzhiyun cb710_write_port_8(slot, CB710_MMC_STATUS2_PORT, 0xFF);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
cb710_mmc_enable_4bit_data(struct cb710_slot * slot,int enable)102*4882a593Smuzhiyun static void cb710_mmc_enable_4bit_data(struct cb710_slot *slot, int enable)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun if (enable)
105*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
106*4882a593Smuzhiyun CB710_MMC_C1_4BIT_DATA_BUS, 0);
107*4882a593Smuzhiyun else
108*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
109*4882a593Smuzhiyun 0, CB710_MMC_C1_4BIT_DATA_BUS);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
cb710_check_event(struct cb710_slot * slot,u8 what)112*4882a593Smuzhiyun static int cb710_check_event(struct cb710_slot *slot, u8 what)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun u16 status;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun status = cb710_read_port_16(slot, CB710_MMC_STATUS_PORT);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (status & CB710_MMC_S0_FIFO_UNDERFLOW) {
119*4882a593Smuzhiyun /* it is just a guess, so log it */
120*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot),
121*4882a593Smuzhiyun "CHECK : ignoring bit 6 in status %04X\n", status);
122*4882a593Smuzhiyun cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT,
123*4882a593Smuzhiyun CB710_MMC_S0_FIFO_UNDERFLOW);
124*4882a593Smuzhiyun status &= ~CB710_MMC_S0_FIFO_UNDERFLOW;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (status & CB710_MMC_STATUS_ERROR_EVENTS) {
128*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot),
129*4882a593Smuzhiyun "CHECK : returning EIO on status %04X\n", status);
130*4882a593Smuzhiyun cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, status & 0xFF);
131*4882a593Smuzhiyun cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT,
132*4882a593Smuzhiyun CB710_MMC_S1_RESET);
133*4882a593Smuzhiyun return -EIO;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /* 'what' is a bit in MMC_STATUS1 */
137*4882a593Smuzhiyun if ((status >> 8) & what) {
138*4882a593Smuzhiyun cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, what);
139*4882a593Smuzhiyun return 1;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun return 0;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
cb710_wait_for_event(struct cb710_slot * slot,u8 what)145*4882a593Smuzhiyun static int cb710_wait_for_event(struct cb710_slot *slot, u8 what)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun int err = 0;
148*4882a593Smuzhiyun unsigned limit = 2000000; /* FIXME: real timeout */
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun #ifdef CONFIG_CB710_DEBUG
151*4882a593Smuzhiyun u32 e, x;
152*4882a593Smuzhiyun e = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
153*4882a593Smuzhiyun #endif
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun while (!(err = cb710_check_event(slot, what))) {
156*4882a593Smuzhiyun if (!--limit) {
157*4882a593Smuzhiyun cb710_dump_regs(cb710_slot_to_chip(slot),
158*4882a593Smuzhiyun CB710_DUMP_REGS_MMC);
159*4882a593Smuzhiyun err = -ETIMEDOUT;
160*4882a593Smuzhiyun break;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun udelay(1);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun #ifdef CONFIG_CB710_DEBUG
166*4882a593Smuzhiyun x = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun limit = 2000000 - limit;
169*4882a593Smuzhiyun if (limit > 100)
170*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot),
171*4882a593Smuzhiyun "WAIT10: waited %d loops, what %d, entry val %08X, exit val %08X\n",
172*4882a593Smuzhiyun limit, what, e, x);
173*4882a593Smuzhiyun #endif
174*4882a593Smuzhiyun return err < 0 ? err : 0;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun
cb710_wait_while_busy(struct cb710_slot * slot,uint8_t mask)178*4882a593Smuzhiyun static int cb710_wait_while_busy(struct cb710_slot *slot, uint8_t mask)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun unsigned limit = 500000; /* FIXME: real timeout */
181*4882a593Smuzhiyun int err = 0;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun #ifdef CONFIG_CB710_DEBUG
184*4882a593Smuzhiyun u32 e, x;
185*4882a593Smuzhiyun e = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
186*4882a593Smuzhiyun #endif
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun while (cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) & mask) {
189*4882a593Smuzhiyun if (!--limit) {
190*4882a593Smuzhiyun cb710_dump_regs(cb710_slot_to_chip(slot),
191*4882a593Smuzhiyun CB710_DUMP_REGS_MMC);
192*4882a593Smuzhiyun err = -ETIMEDOUT;
193*4882a593Smuzhiyun break;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun udelay(1);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun #ifdef CONFIG_CB710_DEBUG
199*4882a593Smuzhiyun x = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun limit = 500000 - limit;
202*4882a593Smuzhiyun if (limit > 100)
203*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot),
204*4882a593Smuzhiyun "WAIT12: waited %d loops, mask %02X, entry val %08X, exit val %08X\n",
205*4882a593Smuzhiyun limit, mask, e, x);
206*4882a593Smuzhiyun #endif
207*4882a593Smuzhiyun return err;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
cb710_mmc_set_transfer_size(struct cb710_slot * slot,size_t count,size_t blocksize)210*4882a593Smuzhiyun static void cb710_mmc_set_transfer_size(struct cb710_slot *slot,
211*4882a593Smuzhiyun size_t count, size_t blocksize)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
214*4882a593Smuzhiyun cb710_write_port_32(slot, CB710_MMC_TRANSFER_SIZE_PORT,
215*4882a593Smuzhiyun ((count - 1) << 16)|(blocksize - 1));
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun dev_vdbg(cb710_slot_dev(slot), "set up for %zu block%s of %zu bytes\n",
218*4882a593Smuzhiyun count, count == 1 ? "" : "s", blocksize);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
cb710_mmc_fifo_hack(struct cb710_slot * slot)221*4882a593Smuzhiyun static void cb710_mmc_fifo_hack(struct cb710_slot *slot)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun /* without this, received data is prepended with 8-bytes of zeroes */
224*4882a593Smuzhiyun u32 r1, r2;
225*4882a593Smuzhiyun int ok = 0;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun r1 = cb710_read_port_32(slot, CB710_MMC_DATA_PORT);
228*4882a593Smuzhiyun r2 = cb710_read_port_32(slot, CB710_MMC_DATA_PORT);
229*4882a593Smuzhiyun if (cb710_read_port_8(slot, CB710_MMC_STATUS0_PORT)
230*4882a593Smuzhiyun & CB710_MMC_S0_FIFO_UNDERFLOW) {
231*4882a593Smuzhiyun cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT,
232*4882a593Smuzhiyun CB710_MMC_S0_FIFO_UNDERFLOW);
233*4882a593Smuzhiyun ok = 1;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot),
237*4882a593Smuzhiyun "FIFO-read-hack: expected STATUS0 bit was %s\n",
238*4882a593Smuzhiyun ok ? "set." : "NOT SET!");
239*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot),
240*4882a593Smuzhiyun "FIFO-read-hack: dwords ignored: %08X %08X - %s\n",
241*4882a593Smuzhiyun r1, r2, (r1|r2) ? "BAD (NOT ZERO)!" : "ok");
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
cb710_mmc_receive_pio(struct cb710_slot * slot,struct sg_mapping_iter * miter,size_t dw_count)244*4882a593Smuzhiyun static int cb710_mmc_receive_pio(struct cb710_slot *slot,
245*4882a593Smuzhiyun struct sg_mapping_iter *miter, size_t dw_count)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun if (!(cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) & CB710_MMC_S2_FIFO_READY)) {
248*4882a593Smuzhiyun int err = cb710_wait_for_event(slot,
249*4882a593Smuzhiyun CB710_MMC_S1_PIO_TRANSFER_DONE);
250*4882a593Smuzhiyun if (err)
251*4882a593Smuzhiyun return err;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun cb710_sg_dwiter_write_from_io(miter,
255*4882a593Smuzhiyun slot->iobase + CB710_MMC_DATA_PORT, dw_count);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun return 0;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
cb710_is_transfer_size_supported(struct mmc_data * data)260*4882a593Smuzhiyun static bool cb710_is_transfer_size_supported(struct mmc_data *data)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun return !(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8));
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
cb710_mmc_receive(struct cb710_slot * slot,struct mmc_data * data)265*4882a593Smuzhiyun static int cb710_mmc_receive(struct cb710_slot *slot, struct mmc_data *data)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun struct sg_mapping_iter miter;
268*4882a593Smuzhiyun size_t len, blocks = data->blocks;
269*4882a593Smuzhiyun int err = 0;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /* TODO: I don't know how/if the hardware handles non-16B-boundary blocks
272*4882a593Smuzhiyun * except single 8B block */
273*4882a593Smuzhiyun if (unlikely(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8)))
274*4882a593Smuzhiyun return -EINVAL;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_TO_SG);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
279*4882a593Smuzhiyun 15, CB710_MMC_C2_READ_PIO_SIZE_MASK);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun cb710_mmc_fifo_hack(slot);
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun while (blocks-- > 0) {
284*4882a593Smuzhiyun len = data->blksz;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun while (len >= 16) {
287*4882a593Smuzhiyun err = cb710_mmc_receive_pio(slot, &miter, 4);
288*4882a593Smuzhiyun if (err)
289*4882a593Smuzhiyun goto out;
290*4882a593Smuzhiyun len -= 16;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun if (!len)
294*4882a593Smuzhiyun continue;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
297*4882a593Smuzhiyun len - 1, CB710_MMC_C2_READ_PIO_SIZE_MASK);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun len = (len >= 8) ? 4 : 2;
300*4882a593Smuzhiyun err = cb710_mmc_receive_pio(slot, &miter, len);
301*4882a593Smuzhiyun if (err)
302*4882a593Smuzhiyun goto out;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun out:
305*4882a593Smuzhiyun sg_miter_stop(&miter);
306*4882a593Smuzhiyun return err;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
cb710_mmc_send(struct cb710_slot * slot,struct mmc_data * data)309*4882a593Smuzhiyun static int cb710_mmc_send(struct cb710_slot *slot, struct mmc_data *data)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun struct sg_mapping_iter miter;
312*4882a593Smuzhiyun size_t len, blocks = data->blocks;
313*4882a593Smuzhiyun int err = 0;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun /* TODO: I don't know how/if the hardware handles multiple
316*4882a593Smuzhiyun * non-16B-boundary blocks */
317*4882a593Smuzhiyun if (unlikely(data->blocks > 1 && data->blksz & 15))
318*4882a593Smuzhiyun return -EINVAL;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_FROM_SG);
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
323*4882a593Smuzhiyun 0, CB710_MMC_C2_READ_PIO_SIZE_MASK);
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun while (blocks-- > 0) {
326*4882a593Smuzhiyun len = (data->blksz + 15) >> 4;
327*4882a593Smuzhiyun do {
328*4882a593Smuzhiyun if (!(cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT)
329*4882a593Smuzhiyun & CB710_MMC_S2_FIFO_EMPTY)) {
330*4882a593Smuzhiyun err = cb710_wait_for_event(slot,
331*4882a593Smuzhiyun CB710_MMC_S1_PIO_TRANSFER_DONE);
332*4882a593Smuzhiyun if (err)
333*4882a593Smuzhiyun goto out;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun cb710_sg_dwiter_read_to_io(&miter,
336*4882a593Smuzhiyun slot->iobase + CB710_MMC_DATA_PORT, 4);
337*4882a593Smuzhiyun } while (--len);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun out:
340*4882a593Smuzhiyun sg_miter_stop(&miter);
341*4882a593Smuzhiyun return err;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
cb710_encode_cmd_flags(struct cb710_mmc_reader * reader,struct mmc_command * cmd)344*4882a593Smuzhiyun static u16 cb710_encode_cmd_flags(struct cb710_mmc_reader *reader,
345*4882a593Smuzhiyun struct mmc_command *cmd)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun unsigned int flags = cmd->flags;
348*4882a593Smuzhiyun u16 cb_flags = 0;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun /* Windows driver returned 0 for commands for which no response
351*4882a593Smuzhiyun * is expected. It happened that there were only two such commands
352*4882a593Smuzhiyun * used: MMC_GO_IDLE_STATE and MMC_GO_INACTIVE_STATE so it might
353*4882a593Smuzhiyun * as well be a bug in that driver.
354*4882a593Smuzhiyun *
355*4882a593Smuzhiyun * Original driver set bit 14 for MMC/SD application
356*4882a593Smuzhiyun * commands. There's no difference 'on the wire' and
357*4882a593Smuzhiyun * it apparently works without it anyway.
358*4882a593Smuzhiyun */
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun switch (flags & MMC_CMD_MASK) {
361*4882a593Smuzhiyun case MMC_CMD_AC: cb_flags = CB710_MMC_CMD_AC; break;
362*4882a593Smuzhiyun case MMC_CMD_ADTC: cb_flags = CB710_MMC_CMD_ADTC; break;
363*4882a593Smuzhiyun case MMC_CMD_BC: cb_flags = CB710_MMC_CMD_BC; break;
364*4882a593Smuzhiyun case MMC_CMD_BCR: cb_flags = CB710_MMC_CMD_BCR; break;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun if (flags & MMC_RSP_BUSY)
368*4882a593Smuzhiyun cb_flags |= CB710_MMC_RSP_BUSY;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun cb_flags |= cmd->opcode << CB710_MMC_CMD_CODE_SHIFT;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
373*4882a593Smuzhiyun cb_flags |= CB710_MMC_DATA_READ;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun if (flags & MMC_RSP_PRESENT) {
376*4882a593Smuzhiyun /* Windows driver set 01 at bits 4,3 except for
377*4882a593Smuzhiyun * MMC_SET_BLOCKLEN where it set 10. Maybe the
378*4882a593Smuzhiyun * hardware can do something special about this
379*4882a593Smuzhiyun * command? The original driver looks buggy/incomplete
380*4882a593Smuzhiyun * anyway so we ignore this for now.
381*4882a593Smuzhiyun *
382*4882a593Smuzhiyun * I assume that 00 here means no response is expected.
383*4882a593Smuzhiyun */
384*4882a593Smuzhiyun cb_flags |= CB710_MMC_RSP_PRESENT;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun if (flags & MMC_RSP_136)
387*4882a593Smuzhiyun cb_flags |= CB710_MMC_RSP_136;
388*4882a593Smuzhiyun if (!(flags & MMC_RSP_CRC))
389*4882a593Smuzhiyun cb_flags |= CB710_MMC_RSP_NO_CRC;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun return cb_flags;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
cb710_receive_response(struct cb710_slot * slot,struct mmc_command * cmd)395*4882a593Smuzhiyun static void cb710_receive_response(struct cb710_slot *slot,
396*4882a593Smuzhiyun struct mmc_command *cmd)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun unsigned rsp_opcode, wanted_opcode;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* Looks like final byte with CRC is always stripped (same as SDHCI) */
401*4882a593Smuzhiyun if (cmd->flags & MMC_RSP_136) {
402*4882a593Smuzhiyun u32 resp[4];
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun resp[0] = cb710_read_port_32(slot, CB710_MMC_RESPONSE3_PORT);
405*4882a593Smuzhiyun resp[1] = cb710_read_port_32(slot, CB710_MMC_RESPONSE2_PORT);
406*4882a593Smuzhiyun resp[2] = cb710_read_port_32(slot, CB710_MMC_RESPONSE1_PORT);
407*4882a593Smuzhiyun resp[3] = cb710_read_port_32(slot, CB710_MMC_RESPONSE0_PORT);
408*4882a593Smuzhiyun rsp_opcode = resp[0] >> 24;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun cmd->resp[0] = (resp[0] << 8)|(resp[1] >> 24);
411*4882a593Smuzhiyun cmd->resp[1] = (resp[1] << 8)|(resp[2] >> 24);
412*4882a593Smuzhiyun cmd->resp[2] = (resp[2] << 8)|(resp[3] >> 24);
413*4882a593Smuzhiyun cmd->resp[3] = (resp[3] << 8);
414*4882a593Smuzhiyun } else {
415*4882a593Smuzhiyun rsp_opcode = cb710_read_port_32(slot, CB710_MMC_RESPONSE1_PORT) & 0x3F;
416*4882a593Smuzhiyun cmd->resp[0] = cb710_read_port_32(slot, CB710_MMC_RESPONSE0_PORT);
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun wanted_opcode = (cmd->flags & MMC_RSP_OPCODE) ? cmd->opcode : 0x3F;
420*4882a593Smuzhiyun if (rsp_opcode != wanted_opcode)
421*4882a593Smuzhiyun cmd->error = -EILSEQ;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
cb710_mmc_transfer_data(struct cb710_slot * slot,struct mmc_data * data)424*4882a593Smuzhiyun static int cb710_mmc_transfer_data(struct cb710_slot *slot,
425*4882a593Smuzhiyun struct mmc_data *data)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun int error, to;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun if (data->flags & MMC_DATA_READ)
430*4882a593Smuzhiyun error = cb710_mmc_receive(slot, data);
431*4882a593Smuzhiyun else
432*4882a593Smuzhiyun error = cb710_mmc_send(slot, data);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun to = cb710_wait_for_event(slot, CB710_MMC_S1_DATA_TRANSFER_DONE);
435*4882a593Smuzhiyun if (!error)
436*4882a593Smuzhiyun error = to;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (!error)
439*4882a593Smuzhiyun data->bytes_xfered = data->blksz * data->blocks;
440*4882a593Smuzhiyun return error;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
cb710_mmc_command(struct mmc_host * mmc,struct mmc_command * cmd)443*4882a593Smuzhiyun static int cb710_mmc_command(struct mmc_host *mmc, struct mmc_command *cmd)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
446*4882a593Smuzhiyun struct cb710_mmc_reader *reader = mmc_priv(mmc);
447*4882a593Smuzhiyun struct mmc_data *data = cmd->data;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun u16 cb_cmd = cb710_encode_cmd_flags(reader, cmd);
450*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "cmd request: 0x%04X\n", cb_cmd);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun if (data) {
453*4882a593Smuzhiyun if (!cb710_is_transfer_size_supported(data)) {
454*4882a593Smuzhiyun data->error = -EINVAL;
455*4882a593Smuzhiyun return -1;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun cb710_mmc_set_transfer_size(slot, data->blocks, data->blksz);
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20|CB710_MMC_S2_BUSY_10);
461*4882a593Smuzhiyun cb710_write_port_16(slot, CB710_MMC_CMD_TYPE_PORT, cb_cmd);
462*4882a593Smuzhiyun cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
463*4882a593Smuzhiyun cb710_write_port_32(slot, CB710_MMC_CMD_PARAM_PORT, cmd->arg);
464*4882a593Smuzhiyun cb710_mmc_reset_events(slot);
465*4882a593Smuzhiyun cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
466*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x01, 0);
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun cmd->error = cb710_wait_for_event(slot, CB710_MMC_S1_COMMAND_SENT);
469*4882a593Smuzhiyun if (cmd->error)
470*4882a593Smuzhiyun return -1;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun if (cmd->flags & MMC_RSP_PRESENT) {
473*4882a593Smuzhiyun cb710_receive_response(slot, cmd);
474*4882a593Smuzhiyun if (cmd->error)
475*4882a593Smuzhiyun return -1;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun if (data)
479*4882a593Smuzhiyun data->error = cb710_mmc_transfer_data(slot, data);
480*4882a593Smuzhiyun return 0;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
cb710_mmc_request(struct mmc_host * mmc,struct mmc_request * mrq)483*4882a593Smuzhiyun static void cb710_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
486*4882a593Smuzhiyun struct cb710_mmc_reader *reader = mmc_priv(mmc);
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun WARN_ON(reader->mrq != NULL);
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun reader->mrq = mrq;
491*4882a593Smuzhiyun cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
494*4882a593Smuzhiyun cb710_mmc_command(mmc, mrq->stop);
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun tasklet_schedule(&reader->finish_req_tasklet);
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
cb710_mmc_powerup(struct cb710_slot * slot)499*4882a593Smuzhiyun static int cb710_mmc_powerup(struct cb710_slot *slot)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun #ifdef CONFIG_CB710_DEBUG
502*4882a593Smuzhiyun struct cb710_chip *chip = cb710_slot_to_chip(slot);
503*4882a593Smuzhiyun #endif
504*4882a593Smuzhiyun int err;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun /* a lot of magic for now */
507*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "bus powerup\n");
508*4882a593Smuzhiyun cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
509*4882a593Smuzhiyun err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
510*4882a593Smuzhiyun if (unlikely(err))
511*4882a593Smuzhiyun return err;
512*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x80, 0);
513*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0x80, 0);
514*4882a593Smuzhiyun cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
515*4882a593Smuzhiyun mdelay(1);
516*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "after delay 1\n");
517*4882a593Smuzhiyun cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
518*4882a593Smuzhiyun err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
519*4882a593Smuzhiyun if (unlikely(err))
520*4882a593Smuzhiyun return err;
521*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x09, 0);
522*4882a593Smuzhiyun cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
523*4882a593Smuzhiyun mdelay(1);
524*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "after delay 2\n");
525*4882a593Smuzhiyun cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
526*4882a593Smuzhiyun err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
527*4882a593Smuzhiyun if (unlikely(err))
528*4882a593Smuzhiyun return err;
529*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0, 0x08);
530*4882a593Smuzhiyun cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
531*4882a593Smuzhiyun mdelay(2);
532*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "after delay 3\n");
533*4882a593Smuzhiyun cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
534*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x06, 0);
535*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x70, 0);
536*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, 0x80, 0);
537*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0x03, 0);
538*4882a593Smuzhiyun cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
539*4882a593Smuzhiyun err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
540*4882a593Smuzhiyun if (unlikely(err))
541*4882a593Smuzhiyun return err;
542*4882a593Smuzhiyun /* This port behaves weird: quick byte reads of 0x08,0x09 return
543*4882a593Smuzhiyun * 0xFF,0x00 after writing 0xFFFF to 0x08; it works correctly when
544*4882a593Smuzhiyun * read/written from userspace... What am I missing here?
545*4882a593Smuzhiyun * (it doesn't depend on write-to-read delay) */
546*4882a593Smuzhiyun cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0xFFFF);
547*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x06, 0);
548*4882a593Smuzhiyun cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
549*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "bus powerup finished\n");
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun return cb710_check_event(slot, 0);
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
cb710_mmc_powerdown(struct cb710_slot * slot)554*4882a593Smuzhiyun static void cb710_mmc_powerdown(struct cb710_slot *slot)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0, 0x81);
557*4882a593Smuzhiyun cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0, 0x80);
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
cb710_mmc_set_ios(struct mmc_host * mmc,struct mmc_ios * ios)560*4882a593Smuzhiyun static void cb710_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
563*4882a593Smuzhiyun struct cb710_mmc_reader *reader = mmc_priv(mmc);
564*4882a593Smuzhiyun int err;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun cb710_mmc_select_clock_divider(mmc, ios->clock);
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (ios->power_mode != reader->last_power_mode) {
569*4882a593Smuzhiyun switch (ios->power_mode) {
570*4882a593Smuzhiyun case MMC_POWER_ON:
571*4882a593Smuzhiyun err = cb710_mmc_powerup(slot);
572*4882a593Smuzhiyun if (err) {
573*4882a593Smuzhiyun dev_warn(cb710_slot_dev(slot),
574*4882a593Smuzhiyun "powerup failed (%d)- retrying\n", err);
575*4882a593Smuzhiyun cb710_mmc_powerdown(slot);
576*4882a593Smuzhiyun udelay(1);
577*4882a593Smuzhiyun err = cb710_mmc_powerup(slot);
578*4882a593Smuzhiyun if (err)
579*4882a593Smuzhiyun dev_warn(cb710_slot_dev(slot),
580*4882a593Smuzhiyun "powerup retry failed (%d) - expect errors\n",
581*4882a593Smuzhiyun err);
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun reader->last_power_mode = MMC_POWER_ON;
584*4882a593Smuzhiyun break;
585*4882a593Smuzhiyun case MMC_POWER_OFF:
586*4882a593Smuzhiyun cb710_mmc_powerdown(slot);
587*4882a593Smuzhiyun reader->last_power_mode = MMC_POWER_OFF;
588*4882a593Smuzhiyun break;
589*4882a593Smuzhiyun case MMC_POWER_UP:
590*4882a593Smuzhiyun default:
591*4882a593Smuzhiyun /* ignore */
592*4882a593Smuzhiyun break;
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun cb710_mmc_enable_4bit_data(slot, ios->bus_width != MMC_BUS_WIDTH_1);
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
cb710_mmc_get_ro(struct mmc_host * mmc)601*4882a593Smuzhiyun static int cb710_mmc_get_ro(struct mmc_host *mmc)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
606*4882a593Smuzhiyun & CB710_MMC_S3_WRITE_PROTECTED;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
cb710_mmc_get_cd(struct mmc_host * mmc)609*4882a593Smuzhiyun static int cb710_mmc_get_cd(struct mmc_host *mmc)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
614*4882a593Smuzhiyun & CB710_MMC_S3_CARD_DETECTED;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
cb710_mmc_irq_handler(struct cb710_slot * slot)617*4882a593Smuzhiyun static int cb710_mmc_irq_handler(struct cb710_slot *slot)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun struct mmc_host *mmc = cb710_slot_to_mmc(slot);
620*4882a593Smuzhiyun struct cb710_mmc_reader *reader = mmc_priv(mmc);
621*4882a593Smuzhiyun u32 status, config1, config2, irqen;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun status = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
624*4882a593Smuzhiyun irqen = cb710_read_port_32(slot, CB710_MMC_IRQ_ENABLE_PORT);
625*4882a593Smuzhiyun config2 = cb710_read_port_32(slot, CB710_MMC_CONFIGB_PORT);
626*4882a593Smuzhiyun config1 = cb710_read_port_32(slot, CB710_MMC_CONFIG_PORT);
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "interrupt; status: %08X, "
629*4882a593Smuzhiyun "ie: %08X, c2: %08X, c1: %08X\n",
630*4882a593Smuzhiyun status, irqen, config2, config1);
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun if (status & (CB710_MMC_S1_CARD_CHANGED << 8)) {
633*4882a593Smuzhiyun /* ack the event */
634*4882a593Smuzhiyun cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT,
635*4882a593Smuzhiyun CB710_MMC_S1_CARD_CHANGED);
636*4882a593Smuzhiyun if ((irqen & CB710_MMC_IE_CISTATUS_MASK)
637*4882a593Smuzhiyun == CB710_MMC_IE_CISTATUS_MASK)
638*4882a593Smuzhiyun mmc_detect_change(mmc, HZ/5);
639*4882a593Smuzhiyun } else {
640*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "unknown interrupt (test)\n");
641*4882a593Smuzhiyun spin_lock(&reader->irq_lock);
642*4882a593Smuzhiyun __cb710_mmc_enable_irq(slot, 0, CB710_MMC_IE_TEST_MASK);
643*4882a593Smuzhiyun spin_unlock(&reader->irq_lock);
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun return 1;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun
cb710_mmc_finish_request_tasklet(unsigned long data)649*4882a593Smuzhiyun static void cb710_mmc_finish_request_tasklet(unsigned long data)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun struct mmc_host *mmc = (void *)data;
652*4882a593Smuzhiyun struct cb710_mmc_reader *reader = mmc_priv(mmc);
653*4882a593Smuzhiyun struct mmc_request *mrq = reader->mrq;
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun reader->mrq = NULL;
656*4882a593Smuzhiyun mmc_request_done(mmc, mrq);
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun static const struct mmc_host_ops cb710_mmc_host = {
660*4882a593Smuzhiyun .request = cb710_mmc_request,
661*4882a593Smuzhiyun .set_ios = cb710_mmc_set_ios,
662*4882a593Smuzhiyun .get_ro = cb710_mmc_get_ro,
663*4882a593Smuzhiyun .get_cd = cb710_mmc_get_cd,
664*4882a593Smuzhiyun };
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun #ifdef CONFIG_PM
667*4882a593Smuzhiyun
cb710_mmc_suspend(struct platform_device * pdev,pm_message_t state)668*4882a593Smuzhiyun static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun cb710_mmc_enable_irq(slot, 0, ~0);
673*4882a593Smuzhiyun return 0;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun
cb710_mmc_resume(struct platform_device * pdev)676*4882a593Smuzhiyun static int cb710_mmc_resume(struct platform_device *pdev)
677*4882a593Smuzhiyun {
678*4882a593Smuzhiyun struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun cb710_mmc_enable_irq(slot, 0, ~0);
681*4882a593Smuzhiyun return 0;
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun #endif /* CONFIG_PM */
685*4882a593Smuzhiyun
cb710_mmc_init(struct platform_device * pdev)686*4882a593Smuzhiyun static int cb710_mmc_init(struct platform_device *pdev)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
689*4882a593Smuzhiyun struct cb710_chip *chip = cb710_slot_to_chip(slot);
690*4882a593Smuzhiyun struct mmc_host *mmc;
691*4882a593Smuzhiyun struct cb710_mmc_reader *reader;
692*4882a593Smuzhiyun int err;
693*4882a593Smuzhiyun u32 val;
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun mmc = mmc_alloc_host(sizeof(*reader), cb710_slot_dev(slot));
696*4882a593Smuzhiyun if (!mmc)
697*4882a593Smuzhiyun return -ENOMEM;
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun platform_set_drvdata(pdev, mmc);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun /* harmless (maybe) magic */
702*4882a593Smuzhiyun pci_read_config_dword(chip->pdev, 0x48, &val);
703*4882a593Smuzhiyun val = cb710_src_freq_mhz[(val >> 16) & 0xF];
704*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "source frequency: %dMHz\n", val);
705*4882a593Smuzhiyun val *= 1000000;
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun mmc->ops = &cb710_mmc_host;
708*4882a593Smuzhiyun mmc->f_max = val;
709*4882a593Smuzhiyun mmc->f_min = val >> cb710_clock_divider_log2[CB710_MAX_DIVIDER_IDX];
710*4882a593Smuzhiyun mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
711*4882a593Smuzhiyun mmc->caps = MMC_CAP_4_BIT_DATA;
712*4882a593Smuzhiyun /*
713*4882a593Smuzhiyun * In cb710_wait_for_event() we use a fixed timeout of ~2s, hence let's
714*4882a593Smuzhiyun * inform the core about it. A future improvement should instead make
715*4882a593Smuzhiyun * use of the cmd->busy_timeout.
716*4882a593Smuzhiyun */
717*4882a593Smuzhiyun mmc->max_busy_timeout = CB710_MMC_REQ_TIMEOUT_MS;
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun reader = mmc_priv(mmc);
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun tasklet_init(&reader->finish_req_tasklet,
722*4882a593Smuzhiyun cb710_mmc_finish_request_tasklet, (unsigned long)mmc);
723*4882a593Smuzhiyun spin_lock_init(&reader->irq_lock);
724*4882a593Smuzhiyun cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun cb710_mmc_enable_irq(slot, 0, ~0);
727*4882a593Smuzhiyun cb710_set_irq_handler(slot, cb710_mmc_irq_handler);
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun err = mmc_add_host(mmc);
730*4882a593Smuzhiyun if (unlikely(err))
731*4882a593Smuzhiyun goto err_free_mmc;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "mmc_hostname is %s\n",
734*4882a593Smuzhiyun mmc_hostname(mmc));
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun cb710_mmc_enable_irq(slot, CB710_MMC_IE_CARD_INSERTION_STATUS, 0);
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun return 0;
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun err_free_mmc:
741*4882a593Smuzhiyun dev_dbg(cb710_slot_dev(slot), "mmc_add_host() failed: %d\n", err);
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun cb710_set_irq_handler(slot, NULL);
744*4882a593Smuzhiyun mmc_free_host(mmc);
745*4882a593Smuzhiyun return err;
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun
cb710_mmc_exit(struct platform_device * pdev)748*4882a593Smuzhiyun static int cb710_mmc_exit(struct platform_device *pdev)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
751*4882a593Smuzhiyun struct mmc_host *mmc = cb710_slot_to_mmc(slot);
752*4882a593Smuzhiyun struct cb710_mmc_reader *reader = mmc_priv(mmc);
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun cb710_mmc_enable_irq(slot, 0, CB710_MMC_IE_CARD_INSERTION_STATUS);
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun mmc_remove_host(mmc);
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun /* IRQs should be disabled now, but let's stay on the safe side */
759*4882a593Smuzhiyun cb710_mmc_enable_irq(slot, 0, ~0);
760*4882a593Smuzhiyun cb710_set_irq_handler(slot, NULL);
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun /* clear config ports - just in case */
763*4882a593Smuzhiyun cb710_write_port_32(slot, CB710_MMC_CONFIG_PORT, 0);
764*4882a593Smuzhiyun cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0);
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun tasklet_kill(&reader->finish_req_tasklet);
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun mmc_free_host(mmc);
769*4882a593Smuzhiyun return 0;
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun static struct platform_driver cb710_mmc_driver = {
773*4882a593Smuzhiyun .driver.name = "cb710-mmc",
774*4882a593Smuzhiyun .probe = cb710_mmc_init,
775*4882a593Smuzhiyun .remove = cb710_mmc_exit,
776*4882a593Smuzhiyun #ifdef CONFIG_PM
777*4882a593Smuzhiyun .suspend = cb710_mmc_suspend,
778*4882a593Smuzhiyun .resume = cb710_mmc_resume,
779*4882a593Smuzhiyun #endif
780*4882a593Smuzhiyun };
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun module_platform_driver(cb710_mmc_driver);
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
785*4882a593Smuzhiyun MODULE_DESCRIPTION("ENE CB710 memory card reader driver - MMC/SD part");
786*4882a593Smuzhiyun MODULE_LICENSE("GPL");
787*4882a593Smuzhiyun MODULE_ALIAS("platform:cb710-mmc");
788