[Armadillo:09056] Re: A-4x0 にSPIでSDカードスロットを増設
Yasuhisa Nakamura
email@hidden
2013年 7月 21日 (日) 00:49:21 JST
中村です。
こんなんところでブロックして(ループして)処理していいのか
わかりませんが、こうやったら動いた、とうパッチです。
まずは、起動時のメッセージ。
...
CSPI: mxc_spi-0 probed
CSPI: mxc_spi-2 probed (今はSPI3は使ってませんが...)
...
mmc_spi spi1.0: ASSUMING SPI bus stays unshared!
mmc_spi spi1.0: ASSUMING 3.2-3.4 V slot power
mmc_spi spi1.0: SD/MMC host mmc1, no DMA
...
mmc_spi_get_cd: return 1 ★
mmc_spi_setpower: maskval = 21 ★
...
mmc_spi_get_ro: return 1 ★
mmc_spi_get_ro: return 1 ★
mmc1: new SD card on SPI
mmcblk0: mmc1:0000 SD02G 1921024KiB (ro)
mmcblk0: p1
★は下のパッチでprintk()しているところです。
2GBのSDカードでテストしてます。
同じカードをArmadillo-460本体のSDカードスロットに装着したときは、
次のようなメッセージが表示されました。
mmc0: new high speed SD card at address 41f1
mmcblk0: mmc0:41f1 SD02G 1921024KiB
mmcblk0: p1
以下、パッチです。
要求バイト数が8バイト(MXC_SPI_FIFO_DEPTH)を超えるときには8バイトで
終わってしまうところを、8バイトを超えるときにはループするように
修正しています。(修正内容を読みやすくするためにgoto使ってます)
--- drivers/spi/mxc_spi.c-orig 2012-07-26 21:30:37.000000000 +0900
+++ drivers/spi/mxc_spi.c 2013-07-20 21:07:14.000000000 +0900
@@ -489,12 +489,15 @@
mxc_spi->transfer.rx_buf = t->rx_buf;
mxc_spi->transfer.len = min_t(u32, t->len, MXC_SPI_FIFO_DEPTH);
mxc_spi->transfer.count = 0;
- INIT_COMPLETION(mxc_spi->xfer_done);
spi_enable_interrupt(mxc_spi, MXC_CSPIINT_RREN);
+ i = 0;
+loop:
+ INIT_COMPLETION(mxc_spi->xfer_done);
+
/* Load up TX FIFO */
- for (i = 0; i < mxc_spi->transfer.len; i++) {
+ for (; i < mxc_spi->transfer.len; i++) {
tx_tmp = mxc_spi->transfer.tx_get(mxc_spi, i);
spi_put_tx_data(mxc_spi->base, tx_tmp);
}
@@ -503,6 +506,13 @@
wait_for_completion(&mxc_spi->xfer_done);
+ if (mxc_spi->transfer.count < t->len) {
+ mxc_spi->transfer.len += min_t(u32,
+ t->len - mxc_spi->transfer.count,
+ MXC_SPI_FIFO_DEPTH);
+ goto loop;
+ }
+
spi_disable_interrupt(mxc_spi, MXC_CSPIINT_RREN);
return mxc_spi->transfer.count;
struct spi_board_infoの設定は、こんな感じです。
read-only検知、カード検知、電源制御は関数を用意しなくても
動くようですが、この後の作業のためにダミーを入れてみました。
max_speed_hzは10MHzとしていますが16MHzまではOKなはずです。
--- arch/arm/mach-mx25/armadillo400.c-orig 2012-07-26 21:30:37.000000000 +0900
+++ arch/arm/mach-mx25/armadillo400.c 2013-07-20 21:38:12.000000000 +0900
@@ -26,6 +26,7 @@
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/fsl_devices.h>
@@ -710,7 +711,41 @@
.chipselect_inactive = gpio_spi1_cs_inactive,
};
+/* とりあえず、常に真を返す */
+static int mmc_spi_get_ro(struct device *dev)
+{
+printk(KERN_INFO "mmc_spi_get_ro: return 1\n");
+ return 1;
+}
+
+/* とりあえず、常に真を返す */
+static int mmc_spi_get_cd(struct device *dev)
+{
+printk(KERN_INFO "mmc_spi_get_cd: return 1\n");
+ return 1;
+}
+
+/* とりあえず、何もしない */
+static void mmc_spi_setpower(struct device *dev, unsigned int maskval)
+{
+printk(KERN_INFO "mmc_spi_setpower: maskval = %d\n", maskval);
+}
+
+static struct mmc_spi_platform_data mmc_spi_info = {
+ .get_ro = mmc_spi_get_ro,
+ .get_cd = mmc_spi_get_cd,
+ .setpower = mmc_spi_setpower,
+};
+
static struct spi_board_info armadillo400_spi1_board_info[] __initdata = {
+ {
+ .modalias = "mmc_spi",
+ .platform_data = &mmc_spi_info,
+ .max_speed_hz = 10000000,
+ .bus_num = 1,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ },
};
#endif
[Armadillo:08970]で書いた、mmc_spi.hの修正です。
--- include/linux/spi/mmc_spi.h-orig 2012-07-26 21:30:37.000000000 +0900
+++ include/linux/spi/mmc_spi.h 2013-07-09 14:19:03.000000000 +0900
@@ -23,6 +23,15 @@
/* sense switch on sd cards */
int (*get_ro)(struct device *);
+ /*
+ * If board does not use CD interrupts, driver can optimize polling
+ * using this function.
+ */
+ int (*get_cd)(struct device *);
+
+ /* Capabilities to pass into mmc core (e.g. MMC_CAP_NEEDS_POLL). */
+ unsigned long caps;
+
/* how long to debounce card detect, in msecs */
u16 detect_delay;
最後に、GPIOによるCS(SS)信号の制御のバグ修正。
--- arch/arm/mach-mx25/armadillo400_gpio.c-orig 2012-07-26 21:30:37.000000000 +0900
+++ arch/arm/mach-mx25/armadillo400_gpio.c 2013-07-20 22:25:30.000000000 +0900
@@ -1480,7 +1480,7 @@
void gpio_spi1_cs_active(int cspi_mode, int chipselect)
{
- int __maybe_unused val = !(cspi_mode & SPI_CPOL);
+ int __maybe_unused val = !!(cspi_mode & SPI_CS_HIGH);
switch (chipselect) {
case 0:
@@ -1504,7 +1504,7 @@
void gpio_spi1_cs_inactive(int cspi_mode, int chipselect)
{
- int __maybe_unused val = !!(cspi_mode & SPI_CPOL);
+ int __maybe_unused val = !(cspi_mode & SPI_CS_HIGH);
switch (chipselect) {
case 0:
@@ -1528,7 +1528,7 @@
void gpio_spi3_cs_active(int cspi_mode, int chipselect)
{
- int __maybe_unused val = !(cspi_mode & SPI_CPOL);
+ int __maybe_unused val = !!(cspi_mode & SPI_CS_HIGH);
switch (chipselect) {
case 0:
@@ -1558,7 +1558,7 @@
void gpio_spi3_cs_inactive(int cspi_mode, int chipselect)
{
- int __maybe_unused val = !!(cspi_mode & SPI_CPOL);
+ int __maybe_unused val = !(cspi_mode & SPI_CS_HIGH);
switch (chipselect) {
case 0:
常にCSがアクティブLOWでいいなら、valとして0か1固定でもいいのです
が(SPI_CPOLを見ているのは間違い)、SPIでSDカードを使うときには、
SPI_CS_HIGHフラグを調べる必要があります。
SDカードをSPIモードで初期化するとききだけ、cspi_modeのSPI_CS_HIGHが
立ちます(CS=HIGHのままreadbytes()でクロックをたくさん出してます)。
これをやっているのが、driver/mmc/host/mmc_spi.cの次の部分です。
static void mmc_spi_initsequence(struct mmc_spi_host *host)
{
...
/*
* Do a burst with chipselect active-high. We need to do this to
* meet the requirement of 74 clock cycles with both chipselect
* and CMD (MOSI) high before CMD0 ... after the card has been
* powered up to Vdd(min), and so is ready to take commands.
(途中省略)
*/
host->spi->mode |= SPI_CS_HIGH;
if (spi_setup(host->spi) != 0) {
エラー処理
} else {
mmc_spi_readbytes(host, 18);
host->spi->mode &= ~SPI_CS_HIGH;
if (spi_setup(host->spi) != 0) {
エラー処理
}
}
}
--
なかむら
armadillo メーリングリストの案内