Skip to contentSkip to conversation

sdio: various bug fixes and CSR specific support

PATCH In review David Vrabel 3 participants 14 messages Aug 10, 2007

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover sdio: various bug fixes and CSR specific support

This set of 5 patches fixes a few bugs in the SDIO support and adds stuff required for CSR chips.

1. SHDC PCI cards produced by Arasan (for prototyping their SHDC IP) report an invalid maximum block size. These cards don't have a valid vendor or device ID so we can't blacklist them. Instead, just assume we can always support a block size of 512 (which is the minimum possible).

2. Ensure we set the bus width the host uses if we set the card's bus width to 4 bit mode. Needless to say a host sending 1 bit mode data to a card in 4 bit mode doesn't work.

3. Add defines for CSR specific CCCR vendor registers.

4. Add vendor and device IDs for CSR chips.

5. Add sdio_f0_readb() and sdio_f0_writeb() so drivers can read/write F0 registers.

David

Signature · 5 lines
David Vrabel, Software Engineer, Drivers group  Tel: +44 (0)1223 692562
CSR plc, Churchill House, Cambridge Business Park, Cowley Road, CB4 0WZ


.
#1 lore raw

mmc: ignore bad max block size in sdhci

Signature · 5 lines
David Vrabel, Software Engineer, Drivers group  Tel: +44 (0)1223 692562
CSR plc, Churchill House, Cambridge Business Park, Cowley Road, CB4 0WZ


.

mmc: ignore bad max block size in sdhci

Some SDHC cards report an invalid maximum block size, in these cases assume they support block sizes up to 512 bytes instead of returning an error.

---

drivers/mmc/host/sdhci.c +4 -5
Index: mmc/drivers/mmc/host/sdhci.c
===================================================================
@@ -1344,12 +1344,11 @@
 	 */
 	mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
 	if (mmc->max_blk_size >= 3) {
-		printk(KERN_ERR "%s: Invalid maximum block size.\n",
+		printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n",
 			host->slot_descr);
-		ret = -ENODEV;
-		goto unmap;
-	}
-	mmc->max_blk_size = 512 << mmc->max_blk_size;
+		mmc->max_blk_size = 512;
+	} else
+		mmc->max_blk_size = 512 << mmc->max_blk_size;
 
 	/*
 	 * Maximum block count.
#3 lore raw

sdio: set host bus width

In reply to David Vrabel
Signature · 5 lines
David Vrabel, Software Engineer, Drivers group  Tel: +44 (0)1223 692562
CSR plc, Churchill House, Cambridge Business Park, Cowley Road, CB4 0WZ


.

sdio: set host bus width

Need to set the bus width used by the host when enabling wide (4 bit) mode.

---

drivers/mmc/core/sdio.c +2 -0
Index: mmc/drivers/mmc/core/sdio.c
===================================================================
@@ -159,6 +159,8 @@
 	if (ret)
 		return ret;
 
+	mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+
 	return 0;
 }
 
#6 lore raw

sdio: add <linux/mmc/sdio_csr.h> for CSR specific CCCR registers

In reply to David Vrabel
Signature · 5 lines
David Vrabel, Software Engineer, Drivers group  Tel: +44 (0)1223 692562
CSR plc, Churchill House, Cambridge Business Park, Cowley Road, CB4 0WZ


.

sdio: add <linux/mmc/sdio_csr.h> for CSR specific CCCR registers

---

include/linux/mmc/sdio_csr.h new file +116 -0
Index: mmc/include/linux/mmc/sdio_csr.h
===================================================================
@@ -0,0 +1,116 @@
+/*
+ * SDIO CCCR vendor registers for CSR chips.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef LINUX_MMC_SDIO_CSR_H
+#define LINUX_MMC_SDIO_CSR_H
+
+/*
+ * Registers at 0xF0 - 0xFF in the CCCR are reserved for vendor
+ * specific registers.  The registers defined here are specific to
+ * following CSR chips:
+ *
+ *   - BlueCore (6 and later)
+ */
+
+/*
+ * Interrupt status/host wakeup register.
+ *
+ * This controls a function's deep sleep state.
+ *
+ * See enum sdio_sleep_state.
+ */
+#define SDIO_CSR_SLEEP_STATE 0xf0
+#  define SDIO_CSR_SLEEP_STATE_FUNC(f) ((f) << 4)
+#  define SDIO_CSR_SLEEP_STATE_RDY_INT_EN  0x02
+#  define SDIO_CSR_SLEEP_STATE_WAKE_REQ    0x01
+
+/*
+ * Host interrupt clear register.
+ *
+ * Writing a 1 to bit 0 clears an SDIO interrupt raised by a generic
+ * function.
+ */
+#define SDIO_CSR_HOST_INT 0xf1
+#  define SDIO_CSR_HOST_INT_CL 0x01
+
+/*
+ * From host scratch registers 0 and 1.
+ *
+ * Read/write registers that can be used for signalling between the
+ * host and the chip.
+ *
+ * The usage of this register depends on the version of the chip or
+ * firmware.
+ */
+#define SDIO_CSR_FROM_HOST_SCRATCH0 0xf2
+#define SDIO_CSR_FROM_HOST_SCRATCH1 0xf3
+
+/*
+ * To host scratch register 0 and 1.
+ *
+ * Read only registers that may be used for signalling between the
+ * chip and the host.
+ *
+ * The usage of this register depends on the version of the chip or
+ * firmware.
+ */
+#define SDIO_CSR_TO_HOST_SCRATCH0 0xf4
+#define SDIO_CSR_TO_HOST_SCRATCH1 0xf5
+
+/*
+ * Extended I/O enable.
+ *
+ * Similar to the standard CCCR I/O Enable register, this is used to
+ * detect if an internal reset of a function has occured and
+ * (optionally) reenable it.
+ *
+ * An internal reset is detected by CCCR I/O Enable bit being set and
+ * the corresponding EXT_IO_EN bit being clear.
+ */
+#define SDIO_CSR_EXT_IO_EN 0xf6
+
+/*
+ * Deep sleep states as set via the sleep state register.
+ *
+ * These states are used to control when the chip may go into a deep
+ * sleep (a low power mode).
+ *
+ * Since a chip in deep sleep may not respond to SDIO commands, the
+ * host should ensure that the chip is not in deep sleep before
+ * attempting SDIO commands to functions 1 to 7.
+ *
+ * The available states are:
+ *
+ * AWAKE - chip must not enter deep sleep and should exit deep sleep
+ * if it's currently sleeping.
+ *
+ * TORPID - chip may enter deep sleep.
+ *
+ * DROWSY - a transition state between TORPID and AWAKE.  This is
+ * AWAKE plus the chip asserts an interrupt when the chip is awake.
+ *
+ * See SDIO_CSR_SLEEP_STATE.
+ */
+enum sdio_csr_sleep_state {
+	SDIO_CSR_SLEEP_STATE_AWAKE  = SDIO_CSR_SLEEP_STATE_WAKE_REQ,
+	SDIO_CSR_SLEEP_STATE_DROWSY = SDIO_CSR_SLEEP_STATE_WAKE_REQ
+	                            | SDIO_CSR_SLEEP_STATE_RDY_INT_EN,
+	SDIO_CSR_SLEEP_STATE_TORPID = 0x00,
+};
+
+#endif /* LINUX_MMC_SDIO_CSR_H */
#10 lore raw

sdio: add CSR vendor/device IDs

In reply to David Vrabel
Signature · 5 lines
David Vrabel, Software Engineer, Drivers group  Tel: +44 (0)1223 692562
CSR plc, Churchill House, Cambridge Business Park, Cowley Road, CB4 0WZ


.

sdio: add CSR vendor/device IDs

---

include/linux/mmc/sdio_ids.h +8 -0
Index: mmc/include/linux/mmc/sdio_ids.h
===================================================================
@@ -19,5 +19,13 @@
 #define SDIO_CLASS_WLAN		0x07	/* WLAN interface */
 #define SDIO_CLASS_ATA		0x08	/* Embedded SDIO-ATA std interface */
 
+/*
+ * Vendor and device IDs.
+ */
+
+#define SDIO_VENDOR_ID_CSR		0x032a
+#define SDIO_DEVICE_ID_CSR_UNIFI_1	0x0001
+#define SDIO_DEVICE_ID_CSR_UNIFI_2	0x0002
+#define SDIO_DEVICE_ID_CSR_BC6		0x0004
 
 #endif
#12 lore raw

PATCH 5/5 sdio: add sdio_f0_readb() and sdio_f0_writeb()

In reply to David Vrabel
Signature · 5 lines
David Vrabel, Software Engineer, Drivers group  Tel: +44 (0)1223 692562
CSR plc, Churchill House, Cambridge Business Park, Cowley Road, CB4 0WZ


.

sdio: add sdio_f0_readb() and sdio_f0_writeb()

Add sdio_f0_readb() and sdio_f0_writeb() functions to reading and writing function 0 registers. Writes outside the vendor specific CCCR registers (0xF0 - 0xFF) are not permitted.

---

drivers/mmc/core/sdio_io.c +66 -0
Index: mmc/drivers/mmc/core/sdio_io.c
===================================================================
@@ -493,3 +493,69 @@
 
 EXPORT_SYMBOL_GPL(sdio_writel);
 
+/**
+ *	sdio_f0_readb - read a single byte from SDIO function 0
+ *	@func: an SDIO function of the card
+ *	@addr: address to read
+ *	@err_ret: optional status value from transfer
+ *
+ *	Reads a single byte from the address space of SDIO function 0.
+ *	If there is a problem reading the address, 0xff is returned
+ *	and @err_ret will contain the error code.
+ */
+unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr,
+	int *err_ret)
+{
+	int ret;
+	unsigned char val;
+
+	BUG_ON(!func);
+
+	if (err_ret)
+		*err_ret = 0;
+
+	ret = mmc_io_rw_direct(func->card, 0, 0, addr, 0, &val);
+	if (ret) {
+		if (err_ret)
+			*err_ret = ret;
+		return 0xFF;
+	}
+
+	return val;
+}
+
+EXPORT_SYMBOL_GPL(sdio_f0_readb);
+
+/**
+ *	sdio_f0_writeb - write a single byte to SDIO function 0
+ *	@func: an SDIO function of the card
+ *	@b: byte to write
+ *	@addr: address to write to
+ *	@err_ret: optional status value from transfer
+ *
+ *	Writes a single byte to the address space of SDIO function 0.
+ *	@err_ret will contain the status of the actual transfer.
+ *
+ *	Only writes to the vendor specific CCCR registers (0xF0 -
+ *	0xFF) are permiited; @err_ret will be set to -EINVAL for *
+ *	writes outside this range.
+ */
+void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
+	int *err_ret)
+{
+	int ret;
+
+	BUG_ON(!func);
+
+	if (addr < 0xF0 || addr > 0xFF) {
+		if (err_ret)
+			*err_ret = -EINVAL;
+		return;
+	}
+
+	ret = mmc_io_rw_direct(func->card, 1, 0, addr, b, NULL);
+	if (err_ret)
+		*err_ret = ret;
+}
+
+EXPORT_SYMBOL_GPL(sdio_f0_writeb);
include/linux/mmc/sdio_func.h +5 -0
Index: mmc/include/linux/mmc/sdio_func.h
===================================================================
@@ -141,5 +141,10 @@
 extern int sdio_writesb(struct sdio_func *func, unsigned int addr,
 	void *src, int count);
 
+extern unsigned char sdio_f0_readb(struct sdio_func *func,
+	unsigned int addr, int *err_ret);
+extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b,
+	unsigned int addr, int *err_ret);
+
 #endif
 
#7 lore raw

Re: sdio: add <linux/mmc/sdio_csr.h> for CSR specific CCCR registers

In reply to David Vrabel

Hi David,

are these CSR extensions specific to Bluetooth or do they also apply to your WiFi and Ultra-Wideband products? If they are Bluetooth specific, we might simply keep them inside the Bluetooth SDIO driver.

Regards

Marcel

#8 lore raw

Re: sdio: add <linux/mmc/sdio_csr.h> for CSR specific CCCR registers

Quoted 5 lines · Marcel Holtmann

Hi David,

are these CSR extensions specific to Bluetooth or do they also apply to your WiFi and Ultra-Wideband products? If they are Bluetooth specific, we might simply keep them inside the Bluetooth SDIO driver.

They're registers common to all chips from BlueCore 6 and upwards. This includes future non-BlueCore/bluetooth products (but not UniFi-1 or UniFi-2).

David

Signature · 5 lines
David Vrabel, Software Engineer, Drivers group  Tel: +44 (0)1223 692562
CSR plc, Churchill House, Cambridge Business Park, Cowley Road, CB4 0WZ


.
#2 lore raw

Re: mmc: ignore bad max block size in sdhci

In reply to David Vrabel
Quoted 7 lines · On Fri, 10 Aug 2007 13:25:03 +0100 David Vrabel <[email protected]> wrote:

mmc: ignore bad max block size in sdhci

Some SDHC cards report an invalid maximum block size, in these cases assume they support block sizes up to 512 bytes instead of returning an error.

Thanks. Applied.

I find it rather amusing that this is for a controller from a vendor that brags about its conformance testing kits. Go figure.

Signature · 5 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org
#4 lore raw

Re: sdio: set host bus width

In reply to David Vrabel
Quoted 6 lines · On Fri, 10 Aug 2007 13:27:34 +0100 David Vrabel <[email protected]> wrote:

sdio: set host bus width

Need to set the bus width used by the host when enabling wide (4 bit) mode.

Now this is just embarrassing. Thanks for spotting it.

Signature · 5 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org
#9 lore raw

Re: sdio: add <linux/mmc/sdio_csr.h> for CSR specific CCCR registers

In reply to David Vrabel
Quoted 3 lines · On Fri, 10 Aug 2007 13:28:18 +0100 David Vrabel <[email protected]> wrote:

sdio: add <linux/mmc/sdio_csr.h> for CSR specific CCCR registers

I'm not a fan of this trend of sticking device specific headers in include/linux, but if it's for registers common to many devices spread all over the kernel tree, then I suppose it's acceptable.

I'm not going to apply this just yet though as it isn't used. Include it with the first driver that needs it.

Signature · 5 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org
#11 lore raw

Re: sdio: add CSR vendor/device IDs

In reply to David Vrabel
Quoted 3 lines · On Fri, 10 Aug 2007 13:28:55 +0100 David Vrabel <[email protected]> wrote:

sdio: add CSR vendor/device IDs

Same thing here. Send it with the driver.

Signature · 5 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org
#13 lore raw

Re: [patch 5/5] sdio: add sdio_f0_readb() and sdio_f0_writeb()

In reply to David Vrabel
Quoted 7 lines · On Fri, 10 Aug 2007 13:29:46 +0100 David Vrabel <[email protected]> wrote:

sdio: add sdio_f0_readb() and sdio_f0_writeb()

Add sdio_f0_readb() and sdio_f0_writeb() functions to reading and writing function 0 registers. Writes outside the vendor specific CCCR registers (0xF0 - 0xFF) are not permitted.

Nice. Especially the touch with restricting it to vendor specific regs. :)

Signature · 5 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org
#5 lore raw

Re: sdio: set host bus width

In reply to Pierre Ossman
Quoted 11 lines · Pierre Ossman
Quoted 6 lines · On Fri, 10 Aug 2007 13:27:34 +0100 David Vrabel <[email protected]> wrote:

sdio: set host bus width

Need to set the bus width used by the host when enabling wide (4 bit) mode.

Now this is just embarrassing. Thanks for spotting it.

Don't feel too bad. I didn't spot it until I started looking at all the data lines with a oscilloscope.

David

Signature · 5 lines
David Vrabel, Software Engineer, Drivers group  Tel: +44 (0)1223 692562
CSR plc, Churchill House, Cambridge Business Park, Cowley Road, CB4 0WZ


.