* OMAP2430sdp MMC driver for 2.6.21
@ 2007-07-23 10:32 石洋
2007-07-23 22:04 ` Syed Mohammed, Khasim
0 siblings, 1 reply; 8+ messages in thread
From: 石洋 @ 2007-07-23 10:32 UTC (permalink / raw)
To: linux-omap-open-source
Hi folks,
I'm doing on OMAP2430sdp MMC driver for 2.6.21.5. I based on minimal OMAP2430 patch on this mailing list and ported twl4030 GPIO and virtual busses drivers form 2.6.14.7. Now kernel works well on my board. I2C also works well on 2.6.21.5, following is I2C log message:
i2c_omap i2c_omap.2: bus 2 rev3.7 at 100 kHz
i2c_omap i2c_omap.1: bus 1 rev3.7 at 100 kHz
TWL4030: TRY attach Slave TWL4030-ID0 on Adapter OMAP I2C adapter[1][1]
TWL4030: TRY attach Slave TWL4030-ID1 on Adapter OMAP I2C adapter[1][1]
TWL4030: TRY attach Slave TWL4030-ID2 on Adapter OMAP I2C adapter[1][1]
TWL4030: TRY attach Slave TWL4030-ID3 on Adapter OMAP I2C adapter[1][1]
TWL4030 Power Companion Active
TWL4030: Driver registration complete.
TWL4030 GPIO Demux: IRQ Range 329 to 338, Initialization Success
56: 0 INTC i2c_omap
57: 130 INTC i2c_omap
So I ported MMC driver from 2.6.14.7. New driver can initialize host coltroller successfully. It seems power supply, clocks and interrupt work well. Following is MMC log message:
Registering OMAP device 'omap2430-mmc12'. Parent at L3
mmc0: set_ios: clock 0Hz busmode 1 powermode 0 Vdd 0 Bus Width 0
Advanced Linux Sound Architecture Driver Version 1.0.14rc3 (Wed Mar 14 07:25:50 2007 UTC).
mmc0: set_ios: clock 0Hz busmode 1 powermode 1 Vdd 15 Bus Width 0
mmc0: set_ios: clock 400000Hz busmode 1 powermode 2 Vdd 15 Bus Width 0
mmc0: set_ios: clock 400000Hz busmode 1 powermode 2 Vdd 15 Bus Width 0
mmc0: set_ios: clock 400000Hz busmode 1 powermode 2 Vdd 15 Bus Width 0
ALSA device list:
OMAP GPIO switch handler initializing
mmc0: set_ios: clock 400000Hz busmode 1 powermode 2 Vdd 14 Bus Width 0
mmc0: set_ios: clock 400000Hz busmode 1 powermode 2 Vdd 14 Bus Width 0
mmc0: set_ios: clock 400000Hz busmode 1 powermode 2 Vdd 14 Bus Width 0
72: 74 INTC serial
83: 114 INTC omap2430-mmc1
309: 2302 GPIO eth0
There is a SD card in slot 1 on my board. But drvier can't detect this card. I printed SYSCTL, CAPA, CUR_CAPA and HCTL registers' values(SYSCTL is e0007. CAPA is 6e10080. CUR_CAPA is 0. HCTL is d00.), they are same as 2.6.14.7. And I enabled debug message for MMC driver. I found driver can send CMD1 command, but CMD1's reponse value always is 0x00ff8000. But according manual, the right reponse value should be 0x80ff8000. So CMD2 is always timeout. Following is the debug message:
...
mmc0: CMD1, argument 0x00300000
, 32-bit response,
Status in IRQ 1
mmc0: Response 00ff8000
mmc0: End request, err 0
mmc0: CMD1, argument 0x00300000
, 32-bit response,
Status in IRQ 1
mmc0: Response 00ff8000
mmc0: End request, err 0
mmc0: CMD2, argument 0x00000000
, 128-bit response, CRC
Status in IRQ 18000
mmc0: Response 00000000 00000000 00000000 00ff8000
mmc0: End request, err 1
mmc0: CMD2, argument 0x00000000
, 128-bit response, CRC
Status in IRQ 18000
mmc0: Response 00000000 00000000 00000000 00ff8000
mmc0: End request, err 1
mmc0: CMD2, argument 0x00000000
, 128-bit response, CRC
Status in IRQ 18000
mmc0: Response 00000000 00000000 00000000 00ff8000
mmc0: End request, err 1
mmc0: CMD2, argument 0x00000000
, 128-bit response, CRC
Status in IRQ 18000
mmc0: Response 00000000 00000000 00000000 00ff8000
mmc0: End request, err 1
mmc0: set_ios: clock 400000Hz busmode 2 powermode 2 Vdd 14 Bus Width 0
mmc0: set_ios: clock 0Hz busmode 1 powermode 0 Vdd 0 Bus Width 0
I suspected the root cause is not in MMC driver, maybe I forgot something else. So could anyone please give me some hints? Thanks.
Best Regards,
Yang Shi
《大 话 西 游 3》 首 届 玩 家 见 面 会 即 将 在 广 州 召 开!敬 请 关 注 >>
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: OMAP2430sdp MMC driver for 2.6.21
2007-07-23 10:32 石洋
@ 2007-07-23 22:04 ` Syed Mohammed, Khasim
0 siblings, 0 replies; 8+ messages in thread
From: Syed Mohammed, Khasim @ 2007-07-23 22:04 UTC (permalink / raw)
To: shy828301, linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 977 bytes --]
>Hi folks,
>
>I'm doing on OMAP2430sdp MMC driver for 2.6.21.5. I based on minimal
>OMAP2430 patch on this mailing list and ported twl4030 GPIO and virtual
>busses drivers form 2.6.14.7. Now kernel works well on my board. I2C also
>works well on 2.6.21.5, following is I2C log message:
>
>mmc0: Response 00ff8000
Looks like your structure is corrupted, this value is default junk value. I was seeing this error with wrong INIT_WORK parameters, note that init_work parameters are changed now.
I suggest you to use twl and I2C drivers from OMAP GIT instead of porting it.
I have a working 2430 MMC code base for Latest OMAP GIT, I am in the process of adopting this to new data structures in include/asm/arch/mmc.h, some how not fitting in straight. But the attached code should work with minimal configuration. Need some cleanups before submitting for comments.
I have not validated SD but MMC is validated for sure. Should help you.
Regards,
Khasim
[-- Attachment #2: board-sdp-hsmmc.c --]
[-- Type: application/octet-stream, Size: 4146 bytes --]
/*
* linux/arch/arm/mach-omap2/board-sdp-hsmmc.c
*
* Copyright (C) 2007 Texas Instruments
* Author: Texas Instruments
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <asm/hardware.h>
#include <asm/arch/twl4030.h>
#include <asm/arch/board.h>
#include <asm/io.h>
#define VMMC1_DEV_GRP 0x27
#define P1_DEV_GRP 0x20
#define VMMC1_DEDICATED 0x2A
#define VSEL_3V 0x02
#define VSEL_18V 0x00
#define TWL_GPIO_PUPDCTR1 0x13
#define TWL_GPIO_IMR1A 0x1C
#define TWL_GPIO_ISR1A 0x19
#define LDO_CLR 0x00
#define VSEL_S2_CLR 0x40
#define GPIO_0_BIT_POS 1 << 0
/*
* Enable power to MMC controller from T2.
* State 1 : Enable Power
* State 0 : Disable Power
*/
int sdp_mmc_power(int state)
{
int ret = 0;
u32 mmc_dev_grp, mmc_dedicated;
mmc_dev_grp = (state == 1) ? P1_DEV_GRP : LDO_CLR;
mmc_dedicated = (state == 1) ? VSEL_3V : VSEL_S2_CLR;
/* For MMC1, Toggle PBIAS before every power up sequence */
omap_writel(omap_readl(CONTROL_PBIAS_LITE_1) & 0x8, CONTROL_PBIAS_LITE_1);
ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
mmc_dev_grp, VMMC1_DEV_GRP);
if (ret != 0)
goto err;
ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
mmc_dedicated, VMMC1_DEDICATED);
if (ret != 0)
goto err;
/* 100ms delay required for PBIAS configuration */
mdelay(100);
omap_writel(omap_readl(CONTROL_PBIAS_LITE_1) | 0x7,
CONTROL_PBIAS_LITE_1);
return ret;
err:
printk(KERN_ERR "Failed to Configure MMC Power\n");
return ret;
}
/*
* Configure TWL4030 GPIO parameters for MMC hotplug irq
*/
int setup_mmc_cd_irq(int irq)
{
int ret = 0;
ret = twl4030_request_gpio(irq);
if (ret != 0)
goto err;
ret = twl4030_set_gpio_edge_ctrl(irq,TWL4030_GPIO_EDGE_RISING |
TWL4030_GPIO_EDGE_FALLING);
if (ret != 0)
goto err;
ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0x02,
TWL_GPIO_PUPDCTR1);
if (ret != 0)
goto err;
ret = twl4030_set_gpio_debounce(irq,TWL4030_GPIO_IS_ENABLE);
if (ret != 0)
goto err;
return ret;
err:
printk(KERN_ERR "Failed to configure TWL4030 GPIO IRQ\n");
return ret;
}
#ifdef CONFIG_PM
/*
* To mask and unmask MMC Card Detect Interrupt
* mask : 1
* unmask : 0
*/
int mask_cd_interrupt(int mask)
{
u8 reg = 0, ret = 0;
ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, ®,TWL_GPIO_IMR1A);
if (ret != 0)
goto err;
reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_IMR1A);
if (ret != 0)
goto err;
ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, ®, TWL_GPIO_ISR1A);
if (ret != 0)
goto err;
reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_ISR1A);
if (ret != 0)
goto err;
return ret;
err:
printk(KERN_ERR "Error configuring TWL4030 Interrupt Mask registers\n");
return ret;
}
#endif
int switch_power_mode(int power_mode)
{
int ret = 0;
u32 reg = 0;
reg = omap_readl(CONTROL_DEVCONF1);
reg = (power_mode == 0) ? (reg & ~(1 << 31)) : (reg | (1 << 31));
omap_writel(reg, CONTROL_DEVCONF1);
omap_writel(omap_readl(CONTROL_PBIAS_LITE_1) & 0x8,
CONTROL_PBIAS_LITE_1);
ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
P1_DEV_GRP, VMMC1_DEV_GRP);
if (ret != 0)
goto err;
reg = (power_mode == 0) ? VSEL_18V : VSEL_3V;
ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, reg,
VMMC1_DEDICATED);
if (ret != 0)
goto err;
mdelay(100);
reg = omap_readl(CONTROL_PBIAS_LITE_1);
reg = (power_mode == 0) ? ((reg | 0x6) & ~0x1) : (reg | 0x7);
omap_writel(reg, CONTROL_PBIAS_LITE_1);
return ret;
err:
printk(KERN_ERR "Configuring MMC1 dedicated failed %x\n", ret);
return ret;
}
EXPORT_SYMBOL(sdp_mmc_power);
EXPORT_SYMBOL(setup_mmc_cd_irq);
EXPORT_SYMBOL(switch_power_mode);
#ifdef CONFIG_PM
EXPORT_SYMBOL(mask_cd_interrupt);
#endif
[-- Attachment #3: omap_hsmmc.c --]
[-- Type: application/octet-stream, Size: 26005 bytes --]
/*
* drivers/mmc/host/omap_hsmmc.c
*
* Driver for OMAP2430 MMC controller.
*
* Copyright (C) 2007 Texas Instruments.
*
* Author:
* Syed Mohammed Khasim <x0khasim@ti.com>
* Madhusudhan <madhu.cr@ti.com>
* Mohit Jalori <mjalori@ti.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sd.h>
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/mach-types.h>
#include <asm/arch/twl4030.h>
#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clock.h>
#include <asm/semaphore.h>
#ifdef CONFIG_PM
#include <linux/notifier.h>
#include <linux/pm.h>
#endif
/* OMAP HSMMC Host Controller Registers */
#define OMAP_HSMMC_SYSCONFIG 0x0010
#define OMAP_HSMMC_CON 0x002C
#define OMAP_HSMMC_BLK 0x0104
#define OMAP_HSMMC_ARG 0x0108
#define OMAP_HSMMC_CMD 0x010C
#define OMAP_HSMMC_RSP10 0x0110
#define OMAP_HSMMC_RSP32 0x0114
#define OMAP_HSMMC_RSP54 0x0118
#define OMAP_HSMMC_RSP76 0x011C
#define OMAP_HSMMC_DATA 0x0120
#define OMAP_HSMMC_HCTL 0x0128
#define OMAP_HSMMC_SYSCTL 0x012C
#define OMAP_HSMMC_STAT 0x0130
#define OMAP_HSMMC_IE 0x0134
#define OMAP_HSMMC_ISE 0x0138
#define OMAP_HSMMC_CAPA 0x0140
#define VS18 (1<<26)
#define VS30 (1<<25)
#define SDVS18 (0x5<<9)
#define SDVS30 (0x6<<9)
#define SDVSCLR 0xFFFFF1FF
#define SDVSDET 0x00000400
#define AUTOIDLE 0x1
#define SDBP (1<<8)
#define DTO 0xe
#define ICE 0x1
#define ICS 0x2
#define CEN (1<<2)
#define CLKD_MASK 0x0000FFC0
#define INT_EN_MASK 0x307F0033
#define INIT_STREAM (1<<1)
#define DP_SELECT (1<<21)
#define DDIR (1<<4)
#define DMA_EN 0x1
#define MSBS 1<<5
#define BCE 1<<1
#define FOUR_BIT 1 << 1
#define CC 0x1
#define TC 0x02
#define OD 0x1
#define ERR (1 << 15)
#define CMD_TIMEOUT (1 << 16)
#define DATA_TIMEOUT (1 << 20)
#define CMD_CRC (1 << 17)
#define DATA_CRC (1 << 21)
#define CARD_ERR (1 << 28)
#define STAT_CLEAR 0xFFFFFFFF
#define INIT_STREAM_CMD 0x00000000
#define OMAP_MMC1_DEVID 1
#define OMAP_MMC2_DEVID 2
#define OMAP_MMC_DATADIR_NONE 0
#define OMAP_MMC_DATADIR_READ 1
#define OMAP_MMC_DATADIR_WRITE 2
#define MMC1_ACTIVE_OVERWRITE (1<<31)
#define MMC_TIMEOUT_MS 20
#define OMAP_MMC_MASTER_CLOCK 96000000
#define DRIVER_NAME "mmci-omap"
/*
* MMC Host controller read/write API's
*/
#define OMAP_HSMMC_READ(base, reg) \
__raw_readl((base) + OMAP_HSMMC_##reg)
#define OMAP_HSMMC_WRITE(base, reg, val) \
__raw_writel((val), (base) + OMAP_HSMMC_##reg)
#if defined(CONFIG_MACH_OMAP_2430SDP)
extern int sdp_mmc_power(int state);
extern int mask_cd_interrupt(int mask);
extern int setup_mmc_cd_irq(int irq);
extern int switch_power_mode(int power_mode);
#endif
struct mmc_omap_host {
struct device *dev;
struct mmc_host *mmc;
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
struct timer_list detect_timer;
struct resource *mem_res;
struct clk *fclk, *iclk, *dbclk;
struct semaphore sem;
struct work_struct mmc_carddetect_work;
void __iomem *base;
void *mapbase;
unsigned int id;
unsigned int dma_len;
unsigned int dma_dir;
unsigned char bus_mode;
unsigned char datadir;
u32 *buffer;
u32 bytesleft;
int suspended;
int irq;
int card_detect_irq;
int use_dma, dma_ch;
int initstream;
};
/*
* Stop clock to the card
*/
static void omap_mmc_stop_clock(struct mmc_omap_host *host)
{
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped");
}
/*
* Send init stream sequence to card
* before sending IDLE command
*/
static void send_init_stream(struct mmc_omap_host *host)
{
int reg = 0;
typeof(jiffies) timeout;
disable_irq(host->irq);
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
while ((reg != CC) && time_before(jiffies, timeout)) {
reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
}
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
enable_irq(host->irq);
}
/*
* Configure the Responce type
*/
static void
mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
{
int cmdreg = 0, resptype = 0, cmdtype = 0;
dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
host->cmd = cmd;
/*
* Clear status bits and enable interrupts
*/
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
switch (mmc_resp_type(cmd)) {
case MMC_RSP_R1:
case MMC_RSP_R3:
case MMC_RSP_R1B:
/* resp 1, 1b, 3 */
resptype = 2;
break;
case MMC_RSP_R2:
resptype = 1;
break;
default:
break;
}
cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base,HCTL) & ~FOUR_BIT);
if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4)
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base,HCTL)
| FOUR_BIT);
else if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_1)
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base,HCTL)
& ~FOUR_BIT);
if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
cmd->opcode == SD_APP_SEND_SCR ||
cmd->opcode == MMC_SEND_EXT_CSD)
cmdreg |= DP_SELECT | DDIR |
MSBS | BCE;
else if (cmd->opcode == MMC_WRITE_BLOCK ||
cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) {
cmdreg |= DP_SELECT | MSBS | BCE;
cmdreg &= ~(DDIR);
}
if (host->use_dma)
cmdreg |= DMA_EN;
if (cmd->opcode == MMC_GO_IDLE_STATE || cmd->opcode == MMC_SEND_OP_COND
|| cmd->opcode == MMC_ALL_SEND_CID)
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) | OD);
if (cmd->opcode == MMC_GO_IDLE_STATE)
if (host->initstream == 0) {
send_init_stream(host);
host->initstream = 1;
}
OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
}
/*
* Notify the transder complete to MMC core
*/
static void
mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
{
host->data = NULL;
if (host->use_dma && host->dma_ch != -1) {
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
host->dma_dir);
}
host->datadir = OMAP_MMC_DATADIR_NONE;
if (data->error == MMC_ERR_NONE)
data->bytes_xfered += data->blocks * (data->blksz);
if (!data->stop) {
host->mrq = NULL;
mmc_request_done(host->mmc, data->mrq);
return;
}
mmc_omap_start_command(host, data->stop);
}
/*
* Notify the core about command completion
*/
static void
mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
{
host->cmd = NULL;
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
/* response type 2 */
cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);
cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
} else {
/* response types 1, 1b, 3, 4, 5, 6 */
cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
}
}
if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
dev_dbg(mmc_dev(host->mmc), "%s: End request, err %x\n",
mmc_hostname(host->mmc), cmd->error);
host->mrq = NULL;
mmc_request_done(host->mmc, cmd->mrq);
}
}
/*
* DMA clean up for command errors
*/
static void mmc_dma_cleanup(struct mmc_omap_host *host)
{
host->data->error |= MMC_ERR_TIMEOUT;
if (host->use_dma && host->dma_ch != -1) {
dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
host->dma_dir);
omap_free_dma(host->dma_ch);
host->dma_ch = -1;
up(&host->sem);
}
host->data = NULL;
host->datadir = OMAP_MMC_DATADIR_NONE;
}
/*
* MMC controller IRQ handler
*/
static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
{
struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
int end_cmd = 0, end_trans = 0, status;
typeof(jiffies) timeout;
if (host->cmd == NULL && host->data == NULL) {
OMAP_HSMMC_WRITE(host->base, STAT,
OMAP_HSMMC_READ(host->base, STAT));
return IRQ_HANDLED;
}
if (host->cmd) {
if (host->cmd->opcode == MMC_SELECT_CARD
|| host->cmd->opcode == MMC_SWITCH) {
timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
while (time_before(jiffies, timeout)) {
if ((OMAP_HSMMC_READ(host->base, STAT)
& CC) == CC)
break;
}
}
}
status = OMAP_HSMMC_READ(host->base, STAT);
dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
if (status & (ERR)) {
if (status & (CMD_TIMEOUT) ||
status & (CMD_CRC)) {
if (host->cmd) {
if (status & (CMD_TIMEOUT))
host->cmd->error |= MMC_ERR_TIMEOUT;
else
host->cmd->error |= MMC_ERR_BADCRC;
end_cmd = 1;
}
if (host->data)
mmc_dma_cleanup(host);
}
if (status & (DATA_TIMEOUT) ||
status & (DATA_CRC)) {
if (host->data) {
if (status & (DATA_TIMEOUT))
mmc_dma_cleanup(host);
else
host->data->error |= MMC_ERR_BADCRC;
end_trans = 1;
}
}
if (status & CARD_ERR) {
if (host->cmd) {
host->cmd->error |= MMC_ERR_FAILED;
end_cmd = 1;
}
if (host->data) {
host->data->error |= MMC_ERR_FAILED;
end_trans = 1;
}
}
}
OMAP_HSMMC_WRITE(host->base, STAT, status);
if (end_cmd || (status & CC))
mmc_omap_cmd_done(host, host->cmd);
if (end_trans || (status & TC))
if (host->mmc->mode == MMC_MODE_MMC
|| host->mmc->mode == MMC_MODE_SD)
mmc_omap_xfer_done(host, host->data);
return IRQ_HANDLED;
}
/* Turn the socket power ON/OFF */
static int mmc_omap_power(struct mmc_omap_host *host, int on)
{
return (sdp_mmc_power(on));
}
/*
* power switching module for mmc slot 1
* power_mode=0 switches to 1.8V
* power_mode=1 switches to 3V
*/
static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int power_mode)
{
u32 reg_val = 0;
/* Disable the clocks */
clk_disable(host->fclk);
clk_disable(host->iclk);
clk_disable(host->dbclk);
if (mmc_omap_power(host,0))
goto err;
if (switch_power_mode(power_mode))
goto err;
clk_enable(host->fclk);
clk_enable(host->iclk);
clk_enable(host->dbclk);
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
reg_val = OMAP_HSMMC_READ(host->base, HCTL);
reg_val |= (power_mode == 0) ? SDVS18 : SDVS30;
OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
if (power_mode)
host->initstream = 0;
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
return 0;
err:
dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage \n");
return -1;
}
/*
* Work Item to notify the core about card insertion/removal
*/
static void mmc_omap_detect(void *data)
{
struct mmc_omap_host *host = (struct mmc_omap_host *)data;
if (twl4030_get_gpio_datain(host->card_detect_irq)) {
if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
if (omap_mmc_switch_opcond(host, 1) != 0)
host->mmc->ios.vdd =
fls(host->mmc->ocr_avail) - 1;
mmc_detect_change(host->mmc, (HZ * 200) / 1000);
}
} else {
mmc_detect_change(host->mmc, (HZ * 50) / 1000);
}
}
/*
* ISR for handling card insertion and removal
*/
static irqreturn_t mmc_omap_irq_cd(int irq, void *dev_id)
{
struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
schedule_work(&host->mmc_carddetect_work);
return IRQ_HANDLED;
}
/*
* DMA call back function
*/
static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
{
struct mmc_omap_host *host = (struct mmc_omap_host *)data;
if (ch_status & (1 << 11))
dev_dbg(mmc_dev(host->mmc), "MISALIGNED_ADRS_ERR\n");
if (host->dma_ch < 0)
return;
omap_free_dma(host->dma_ch);
host->dma_ch = -1;
up(&host->sem);
}
/*
* Configure dma src and destination parameters
*/
static int mmc_omap_config_dma_param(int sync_dir, struct mmc_omap_host *host,
struct mmc_data *data)
{
if (sync_dir == 0) {
omap_set_dma_dest_params(host->dma_ch, 0,
OMAP_DMA_AMODE_CONSTANT,
(dma_addr_t) (host-> mapbase + OMAP_HSMMC_DATA), 0, 0);
omap_set_dma_src_params(host->dma_ch, 0,
OMAP_DMA_AMODE_POST_INC,
sg_dma_address(&data-> sg[0]), 0, 0);
} else {
omap_set_dma_src_params(host->dma_ch, 0,
OMAP_DMA_AMODE_CONSTANT,
(dma_addr_t) (host->mapbase +OMAP_HSMMC_DATA), 0, 0);
omap_set_dma_dest_params(host->dma_ch, 0,
OMAP_DMA_AMODE_POST_INC,
sg_dma_address(&data->sg[0]), 0, 0);
}
return 0;
}
/*
* Rotine to configure and start DMA for the MMC card
*/
static int
mmc_omap_start_dma_transfer(struct mmc_omap_host *host, struct mmc_request *req)
{
int sync_dev, sync_dir, dma_ch, ret;
struct mmc_data *data = req->data;
/*
* If for some reason the DMA transfer is still active,
* we wait for timeout period and free the dma
*/
if (host->dma_ch != -1) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(100);
if (down_trylock(&host->sem)) {
omap_free_dma(host->dma_ch);
host->dma_ch = -1;
up(&host->sem);
return 1;
}
} else {
if (down_trylock(&host->sem)) {
BUG();
}
}
if (!(data->flags & MMC_DATA_WRITE)) {
host->dma_dir = DMA_FROM_DEVICE;
if (host->id == OMAP_MMC1_DEVID)
sync_dev = OMAP24XX_DMA_MMC1_RX;
else
sync_dev = OMAP24XX_DMA_MMC2_RX;
} else {
host->dma_dir = DMA_TO_DEVICE;
if (host->id == OMAP_MMC1_DEVID)
sync_dev = OMAP24XX_DMA_MMC1_TX;
else
sync_dev = OMAP24XX_DMA_MMC2_TX;
}
ret = omap_request_dma(sync_dev, "MMC/SD", mmc_omap_dma_cb,
host, &dma_ch);
if (ret != 0) {
dev_dbg(mmc_dev(host->mmc),
"%s: omap_request_dma() failed with %d\n",
mmc_hostname(host->mmc), ret);
return ret;
}
host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
data->sg_len, host->dma_dir);
host->dma_ch = dma_ch;
if (!(data->flags & MMC_DATA_WRITE))
mmc_omap_config_dma_param(1, host, data);
else
mmc_omap_config_dma_param(0, host, data);
omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32,
(data->blksz / 4), data->blocks, OMAP_DMA_SYNC_FRAME,
sync_dev, sync_dir);
omap_start_dma(dma_ch);
return 0;
}
/*
* Configure block leangth for MMC/SD cards and intiate the transfer.
*/
static int
mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
{
int ret = 0;
host->data = req->data;
if (req->data == NULL) {
host->datadir = OMAP_MMC_DATADIR_NONE;
OMAP_HSMMC_WRITE(host->base, BLK, 0);
return 0;
}
OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
| (req->data->blocks << 16) );
host->datadir = (req->data-> flags & MMC_DATA_WRITE) ?
OMAP_MMC_DATADIR_WRITE : OMAP_MMC_DATADIR_READ;
if (host->use_dma) {
ret = mmc_omap_start_dma_transfer(host, req);
if (ret != 0) {
dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
return ret;
} else {
host->buffer = NULL;
host->bytesleft = 0;
}
} else {
host->buffer = (u32 *) (page_address(req->data->sg->page) +
req->data->sg->offset);
host->bytesleft = req->data->blocks * (req->data->blksz);
host->dma_ch = -1;
}
return 0;
}
/* Request function. Exposed API to core for read/write operation */
static void omap_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
{
struct mmc_omap_host *host = mmc_priv(mmc);
WARN_ON(host->mrq != NULL);
host->mrq = req;
/* Reset MMC Controller's Data FSM */
if (req->cmd->opcode == MMC_GO_IDLE_STATE) {
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | 1 << 26);
while (OMAP_HSMMC_READ(host->base, SYSCTL) & (1 << 26)) ;
}
if (req->cmd->opcode == SD_APP_SEND_SCR
|| req->cmd->opcode == MMC_SEND_EXT_CSD)
mmc->ios.bus_width = MMC_BUS_WIDTH_1;
if (mmc_omap_prepare_data(host, req))
dev_dbg(mmc_dev(host->mmc),
"MMC host %s failed to initiate data transfer\n",
mmc_hostname(host->mmc));
mmc_omap_start_command(host, req->cmd);
}
/* Routine to configure clock values. Exposed API to core */
static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct mmc_omap_host *host = mmc_priv(mmc);
u16 dsor = 0;
unsigned long reg_val = 0;
typeof(jiffies) timeout;
mmc_omap_power(host, ios->power_mode);
/*
switch (ios->power_mode) {
case MMC_POWER_OFF:
if (mmc_omap_power(host, 0))
dev_dbg(mmc_dev(host->mmc),
"Could not disable power to MMC%d\n",host->id);
break;
case MMC_POWER_UP:
if (mmc_omap_power(host, 1))
dev_dbg(mmc_dev(host->mmc),
"Could not enable power to MMC%d\n",host->id);
break;
}*/
if (host->id == OMAP_MMC1_DEVID) {
if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
((ios->vdd == 7) || (ios->vdd == 8))) {
if (omap_mmc_switch_opcond(host, 0) != 0)
dev_dbg(mmc_dev(host->mmc),
"omap_mmc_set_ios:"
"switch operation failed\n");
host->initstream = 0;
}
}
if (ios->clock) {
dsor = OMAP_MMC_MASTER_CLOCK / ios->clock;
if (dsor < 1)
dsor = 1;
if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
dsor++;
if (dsor > 250)
dsor = 250;
}
omap_mmc_stop_clock(host);
reg_val = OMAP_HSMMC_READ(host->base, SYSCTL);
reg_val = reg_val & ~(CLKD_MASK);
reg_val = reg_val | (dsor << 6);
reg_val = reg_val | (DTO << 16);
OMAP_HSMMC_WRITE(host->base, SYSCTL, reg_val);
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
/* wait till the ICS bit is set */
timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != 0x2
&& time_before(jiffies, timeout)) ;
/* Enable clock to the card */
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
}
static struct mmc_host_ops mmc_omap_ops = {
.request = omap_mmc_request,
.set_ios = omap_mmc_set_ios,
};
static int __init omap_mmc_probe(struct platform_device *pdev)
{
struct omap_mmc_conf *minfo = pdev->dev.platform_data;
struct mmc_host *mmc;
struct mmc_omap_host *host = NULL;
struct resource *res;
int ret = 0, irq, *addr;
u32 dvs = 0;
if (minfo == NULL) {
dev_err(&pdev->dev, "Platform Data is missing\n");
return -ENXIO;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (res == NULL || irq < 0)
return -ENXIO;
res = request_mem_region(res->start, res->end - res->start + 1,
pdev->name);
if (res == NULL)
return -EBUSY;
mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
if (!mmc) {
ret = -ENOMEM;
goto err;
}
host = mmc_priv(mmc);
host->mmc = mmc;
sema_init(&host->sem, 1);
host->use_dma = 1;
host->dma_ch = -1;
host->initstream = 0;
host->mem_res = res;
host->irq = irq;
host->id = pdev->id;
host->mapbase = (void *)host->mem_res->start;
host->base = (void __iomem *)IO_ADDRESS(host->mapbase);
mmc->ops = &mmc_omap_ops;
mmc->f_min = 400000;
mmc->f_max = 52000000;
printk(" In MMC driver %d \n",pdev->id);
host->iclk = clk_get(&pdev->dev, "mmchs_ick");
if (IS_ERR(host->iclk)) {
ret = PTR_ERR(host->iclk);
host->iclk = NULL;
goto err;
}
host->fclk = clk_get(&pdev->dev, "mmchs_fck");
if (IS_ERR(host->fclk)) {
ret = PTR_ERR(host->fclk);
host->fclk = NULL;
clk_put(host->iclk);
goto err;
}
host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
/*
* MMC can still work without debounce clock.
*/
if (IS_ERR(host->dbclk))
dev_dbg(mmc_dev(host->mmc), "Failed to get debounce clock \n");
if (clk_enable(host->fclk) != 0) {
goto err;
}
if (clk_enable(host->iclk) != 0) {
clk_disable(host->fclk);
clk_put(host->fclk);
goto err;
}
if (clk_enable(host->dbclk) != 0)
dev_dbg(mmc_dev(host->mmc), "Enabling debounce clk failed\n");
omap_writel(omap_readl(CONTROL_DEVCONF1) | MMC1_ACTIVE_OVERWRITE,
CONTROL_DEVCONF1);
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
mmc->caps |= MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
if (minfo->wire4)
mmc->caps = MMC_CAP_4_BIT_DATA;
dvs = (host->id == OMAP_MMC1_DEVID) ? SDVS30 : SDVS18;
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) | dvs);
OMAP_HSMMC_WRITE(host->base, CAPA,OMAP_HSMMC_READ(host->base,
CAPA) | VS30 | VS18);
/* Set the controller to AUTO IDLE mode */
OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
/* Set SD bus power bit */
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
/* Request IRQ for MMC operations */
ret = request_irq(host->irq, mmc_omap_irq, 0, pdev->name, host);
if (ret) {
dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ");
goto irq_err;
}
if (minfo->switch_pin >= 0) {
host->card_detect_irq =
TWL4030_GPIO_IRQ_NO(minfo->switch_pin);
INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
if (setup_mmc_cd_irq(minfo->switch_pin)) {
free_irq(host->irq, host);
goto irq_err;
}
ret = request_irq(host->card_detect_irq,
mmc_omap_irq_cd, IRQF_DISABLED, pdev->name,host);
if (ret < 0) {
free_irq(host->irq, host);
goto irq_err;
}
}
OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
platform_set_drvdata(pdev, host);
mmc_add_host(mmc);
return 0;
err:
dev_dbg(mmc_dev(host->mmc), "Probe unsuccessful\n");
if (host)
mmc_free_host(mmc);
return ret;
irq_err:
dev_dbg(mmc_dev(host->mmc), "Unable to configure MMC IRQs");
clk_disable(host->fclk);
clk_disable(host->iclk);
clk_disable(host->dbclk);
clk_put(host->fclk);
clk_put(host->iclk);
clk_put(host->dbclk);
if (host)
mmc_free_host(mmc);
return ret;
}
static int omap_mmc_remove(struct platform_device *pdev)
{
struct mmc_omap_host *host = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
if (host) {
free_irq(host->irq, host);
free_irq(host->card_detect_irq, host);
flush_scheduled_work();
clk_disable(host->fclk);
clk_disable(host->iclk);
clk_disable(host->dbclk);
clk_put(host->fclk);
clk_put(host->iclk);
clk_put(host->dbclk);
mmc_free_host(host->mmc);
}
return 0;
}
#ifdef CONFIG_PM
static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state)
{
int ret = 0;
struct mmc_omap_host *host = platform_get_drvdata(pdev);
if (host && host->suspended)
return 0;
if (host) {
/* Notify the core to suspend the host */
ret = mmc_suspend_host(host->mmc, state);
if (ret == 0) {
host->suspended = 1;
/* Disable Interrupts */
OMAP_HSMMC_WRITE(host->base, ISE, 0);
OMAP_HSMMC_WRITE(host->base, IE, 0);
disable_irq(host->card_detect_irq);
ret = mask_cd_interrupt(1);
if (ret)
dev_dbg(mmc_dev(host->mmc),
"Unable to mask the card detect"
"interrupt in suspend\n");
if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
OMAP_HSMMC_WRITE(host->base,HCTL,
OMAP_HSMMC_READ(host->base,HCTL)
& SDVSCLR);
OMAP_HSMMC_WRITE(host->base,HCTL,
OMAP_HSMMC_READ(host->base,HCTL)
|SDVS30);
OMAP_HSMMC_WRITE(host->base,HCTL,
OMAP_HSMMC_READ(host->base,HCTL)
| SDBP);
}
/* disable clks for MMC1 */
clk_disable(host->fclk);
clk_disable(host->iclk);
clk_disable(host->dbclk);
if (host->id == OMAP_MMC1_DEVID) {
omap_writel(omap_readl(CONTROL_DEVCONF1)
& ~MMC1_ACTIVE_OVERWRITE,
CONTROL_DEVCONF1);
}
ret = mmc_omap_power(host,0);
if (ret != 0)
dev_dbg(mmc_dev(host->mmc),
"Unable to disable power to MMC1\n");
host->initstream = 0;
}
}
return ret;
}
/* Routine to resume the MMC device */
static int omap_mmc_resume(struct platform_device *pdev)
{
int ret = 0;
struct mmc_omap_host *host = platform_get_drvdata(pdev);
if (host && !host->suspended)
return 0;
if (host) {
if (host->id == OMAP_MMC1_DEVID) {
omap_writel(omap_readl(CONTROL_DEVCONF1)
| MMC1_ACTIVE_OVERWRITE,
CONTROL_DEVCONF1);
}
ret = mmc_omap_power(host,1);
if (ret != 0) {
dev_dbg(mmc_dev(host->mmc), "Enabling power failed\n");
return ret;
}
if (clk_enable(host->fclk) != 0)
goto clk_en_err;
if (clk_enable(host->iclk) != 0) {
clk_disable(host->fclk);
clk_put(host->fclk);
goto clk_en_err;
}
if (clk_enable(host->dbclk) != 0)
dev_dbg(mmc_dev(host->mmc),
"Enabling debounce clk failed\n");
enable_irq(host->card_detect_irq);
ret = mask_cd_interrupt(0);
if (ret)
dev_dbg(mmc_dev(host->mmc),
"Unmask interrupt failed\n");
/* Notify the core to resume the host */
ret = mmc_resume_host(host->mmc);
if (ret == 0)
host->suspended = 0;
msleep_interruptible(1);
}
return ret;
clk_en_err:
dev_dbg(mmc_dev(host->mmc),
"Unable to enable MMC clocks during resume\n");
return -1;
}
#else
#define omap_mmc_suspend NULL
#define omap_mmc_resume NULL
#endif
static struct platform_driver omap_mmc_driver = {
.probe = omap_mmc_probe,
.remove = omap_mmc_remove,
.suspend= omap_mmc_suspend,
.resume = omap_mmc_resume,
.driver = {
.name = DRIVER_NAME,
},
};
static int __init omap_mmc_init(void)
{
/* Register the MMC driver */
if (platform_driver_register(&omap_mmc_driver)) {
printk(KERN_ERR ":failed to register MMC driver\n");
return -ENODEV;
}
return 0;
}
static void __exit omap_mmc_cleanup(void)
{
/* Unregister MMC driver */
platform_driver_unregister(&omap_mmc_driver);
}
module_init(omap_mmc_init);
module_exit(omap_mmc_cleanup);
MODULE_DESCRIPTION("OMAP 2430 Multimedia Card driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS(DRIVER_NAME);
MODULE_AUTHOR("Texas Instruments");
[-- Attachment #4: devices.c --]
[-- Type: application/octet-stream, Size: 13672 bytes --]
/*
* linux/arch/arm/plat-omap/devices.c
*
* Common platform device setup/initialization for OMAP1 and OMAP2
*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
#include <asm/arch/tc.h>
#include <asm/arch/board.h>
#include <asm/arch/mux.h>
#include <asm/arch/gpio.h>
#include <asm/arch/menelaus.h>
#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
#include "../plat-omap/dsp/dsp_common.h"
static struct dsp_platform_data dsp_pdata = {
.kdev_list = LIST_HEAD_INIT(dsp_pdata.kdev_list),
};
static struct resource omap_dsp_resources[] = {
{
.name = "dsp_mmu",
.start = -1,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device omap_dsp_device = {
.name = "dsp",
.id = -1,
.num_resources = ARRAY_SIZE(omap_dsp_resources),
.resource = omap_dsp_resources,
.dev = {
.platform_data = &dsp_pdata,
},
};
static inline void omap_init_dsp(void)
{
struct resource *res;
int irq;
if (cpu_is_omap15xx())
irq = INT_1510_DSP_MMU;
else if (cpu_is_omap16xx())
irq = INT_1610_DSP_MMU;
else if (cpu_is_omap24xx())
irq = INT_24XX_DSP_MMU;
res = platform_get_resource_byname(&omap_dsp_device,
IORESOURCE_IRQ, "dsp_mmu");
res->start = irq;
platform_device_register(&omap_dsp_device);
}
int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev)
{
static DEFINE_MUTEX(dsp_pdata_lock);
spin_lock_init(&kdev->lock);
mutex_lock(&dsp_pdata_lock);
list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
mutex_unlock(&dsp_pdata_lock);
return 0;
}
EXPORT_SYMBOL(dsp_kfunc_device_register);
#else
static inline void omap_init_dsp(void) { }
#endif /* CONFIG_OMAP_DSP */
/*-------------------------------------------------------------------------*/
#if !defined(CONFIG_ARCH_OMAP243X)
#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
#define OMAP1_I2C_BASE 0xfffb3800
#define OMAP2_I2C_BASE1 0x48070000
#define OMAP_I2C_SIZE 0x3f
#define OMAP1_I2C_INT INT_I2C
#define OMAP2_I2C_INT1 56
static u32 omap2_i2c1_clkrate = 100;
static struct resource i2c_resources1[] = {
{
.start = 0,
.end = 0,
.flags = IORESOURCE_MEM,
},
{
.start = 0,
.flags = IORESOURCE_IRQ,
},
};
/* DMA not used; works around erratum writing to non-empty i2c fifo */
static struct platform_device omap_i2c_device1 = {
.name = "i2c_omap",
.id = 1,
.num_resources = ARRAY_SIZE(i2c_resources1),
.resource = i2c_resources1,
.dev = {
.platform_data = &omap2_i2c1_clkrate,
},
};
/* See also arch/arm/mach-omap2/devices.c for second I2C on 24xx */
static void omap_init_i2c(void)
{
if (cpu_is_omap242x()) {
i2c_resources1[0].start = OMAP2_I2C_BASE1;
i2c_resources1[0].end = OMAP2_I2C_BASE1 + OMAP_I2C_SIZE;
i2c_resources1[1].start = OMAP2_I2C_INT1;
} else {
i2c_resources1[0].start = OMAP1_I2C_BASE;
i2c_resources1[0].end = OMAP1_I2C_BASE + OMAP_I2C_SIZE;
i2c_resources1[1].start = OMAP1_I2C_INT;
}
/* FIXME define and use a boot tag, in case of boards that
* either don't wire up I2C, or chips that mux it differently...
* it can include clocking and address info, maybe more.
*/
if (cpu_class_is_omap2()) {
if (machine_is_omap_h4()) {
omap_cfg_reg(M19_24XX_I2C1_SCL);
omap_cfg_reg(L15_24XX_I2C1_SDA);
}
} else {
omap_cfg_reg(I2C_SCL);
omap_cfg_reg(I2C_SDA);
}
(void) platform_device_register(&omap_i2c_device1);
}
#else
static inline void omap_init_i2c(void) {}
#endif
#endif
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE)
static void omap_init_kp(void)
{
/* REVISIT: 2430 keypad is on TWL4030 */
if (cpu_is_omap2430() || cpu_is_omap34xx())
return;
if (machine_is_omap_h2() || machine_is_omap_h3()) {
omap_cfg_reg(F18_1610_KBC0);
omap_cfg_reg(D20_1610_KBC1);
omap_cfg_reg(D19_1610_KBC2);
omap_cfg_reg(E18_1610_KBC3);
omap_cfg_reg(C21_1610_KBC4);
omap_cfg_reg(G18_1610_KBR0);
omap_cfg_reg(F19_1610_KBR1);
omap_cfg_reg(H14_1610_KBR2);
omap_cfg_reg(E20_1610_KBR3);
omap_cfg_reg(E19_1610_KBR4);
omap_cfg_reg(N19_1610_KBR5);
} else if (machine_is_omap_perseus2() || machine_is_omap_fsample()) {
omap_cfg_reg(E2_730_KBR0);
omap_cfg_reg(J7_730_KBR1);
omap_cfg_reg(E1_730_KBR2);
omap_cfg_reg(F3_730_KBR3);
omap_cfg_reg(D2_730_KBR4);
omap_cfg_reg(C2_730_KBC0);
omap_cfg_reg(D3_730_KBC1);
omap_cfg_reg(E4_730_KBC2);
omap_cfg_reg(F4_730_KBC3);
omap_cfg_reg(E3_730_KBC4);
} else if (machine_is_omap_h4()) {
omap_cfg_reg(T19_24XX_KBR0);
omap_cfg_reg(R19_24XX_KBR1);
omap_cfg_reg(V18_24XX_KBR2);
omap_cfg_reg(M21_24XX_KBR3);
omap_cfg_reg(E5__24XX_KBR4);
if (omap_has_menelaus()) {
omap_cfg_reg(B3__24XX_KBR5);
omap_cfg_reg(AA4_24XX_KBC2);
omap_cfg_reg(B13_24XX_KBC6);
} else {
omap_cfg_reg(M18_24XX_KBR5);
omap_cfg_reg(H19_24XX_KBC2);
omap_cfg_reg(N19_24XX_KBC6);
}
omap_cfg_reg(R20_24XX_KBC0);
omap_cfg_reg(M14_24XX_KBC1);
omap_cfg_reg(V17_24XX_KBC3);
omap_cfg_reg(P21_24XX_KBC4);
omap_cfg_reg(L14_24XX_KBC5);
}
}
#else
static inline void omap_init_kp(void) {}
#endif
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
#ifdef CONFIG_ARCH_OMAP24XX
#define OMAP_MMC1_BASE 0x4809c000
#define OMAP_MMC1_INT INT_24XX_MMC_IRQ
#else
#define OMAP_MMC1_BASE 0xfffb7800
#define OMAP_MMC1_INT INT_MMC
#endif
#define OMAP_MMC2_BASE 0xfffb7c00 /* omap16xx only */
static struct omap_mmc_conf mmc1_conf;
static u64 mmc1_dmamask = 0xffffffff;
static struct resource mmc1_resources[] = {
{
.start = OMAP_MMC1_BASE,
.end = OMAP_MMC1_BASE + 0x7f,
.flags = IORESOURCE_MEM,
},
{
.start = OMAP_MMC1_INT,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mmc_omap_device1 = {
.name = "mmci-omap",
.id = 1,
.dev = {
.dma_mask = &mmc1_dmamask,
.platform_data = &mmc1_conf,
},
.num_resources = ARRAY_SIZE(mmc1_resources),
.resource = mmc1_resources,
};
#ifdef CONFIG_ARCH_OMAP16XX
static struct omap_mmc_conf mmc2_conf;
static u64 mmc2_dmamask = 0xffffffff;
static struct resource mmc2_resources[] = {
{
.start = OMAP_MMC2_BASE,
.end = OMAP_MMC2_BASE + 0x7f,
.flags = IORESOURCE_MEM,
},
{
.start = INT_1610_MMC2,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mmc_omap_device2 = {
.name = "mmci-omap",
.id = 2,
.dev = {
.dma_mask = &mmc2_dmamask,
.platform_data = &mmc2_conf,
},
.num_resources = ARRAY_SIZE(mmc2_resources),
.resource = mmc2_resources,
};
#endif
static void __init omap_init_mmc(void)
{
const struct omap_mmc_config *mmc_conf;
const struct omap_mmc_conf *mmc;
/* REVISIT: 3430 HS MMC is TBD */
if (cpu_is_omap34xx())
return;
/* NOTE: assumes MMC was never (wrongly) enabled */
mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config);
if (!mmc_conf)
return;
/* block 1 is always available and has just one pinout option */
mmc = &mmc_conf->mmc[0];
if (mmc->enabled) {
if (cpu_is_omap242x()) {
omap_cfg_reg(H18_24XX_MMC_CMD);
omap_cfg_reg(H15_24XX_MMC_CLKI);
omap_cfg_reg(G19_24XX_MMC_CLKO);
omap_cfg_reg(F20_24XX_MMC_DAT0);
omap_cfg_reg(F19_24XX_MMC_DAT_DIR0);
omap_cfg_reg(G18_24XX_MMC_CMD_DIR);
} else {
omap_cfg_reg(MMC_CMD);
omap_cfg_reg(MMC_CLK);
omap_cfg_reg(MMC_DAT0);
if (cpu_is_omap1710()) {
omap_cfg_reg(M15_1710_MMC_CLKI);
omap_cfg_reg(P19_1710_MMC_CMDDIR);
omap_cfg_reg(P20_1710_MMC_DATDIR0);
}
}
if (mmc->wire4) {
if (cpu_is_omap242x()) {
omap_cfg_reg(H14_24XX_MMC_DAT1);
omap_cfg_reg(E19_24XX_MMC_DAT2);
omap_cfg_reg(D19_24XX_MMC_DAT3);
omap_cfg_reg(E20_24XX_MMC_DAT_DIR1);
omap_cfg_reg(F18_24XX_MMC_DAT_DIR2);
omap_cfg_reg(E18_24XX_MMC_DAT_DIR3);
} else {
omap_cfg_reg(MMC_DAT1);
/* NOTE: DAT2 can be on W10 (here) or M15 */
if (!mmc->nomux)
omap_cfg_reg(MMC_DAT2);
omap_cfg_reg(MMC_DAT3);
}
}
if (mmc->internal_clock) {
/*
* Use internal loop-back in MMC/SDIO
* Module Input Clock selection
*/
if (cpu_is_omap242x()) {
u32 v = omap_readl(OMAP24XX_CONTROL_DEVCONF);
v |= (1 << 24);
omap_writel(v, OMAP24XX_CONTROL_DEVCONF);
}
}
mmc1_conf = *mmc;
(void) platform_device_register(&mmc_omap_device1);
}
#ifdef CONFIG_ARCH_OMAP16XX
/* block 2 is on newer chips, and has many pinout options */
mmc = &mmc_conf->mmc[1];
if (mmc->enabled) {
if (!mmc->nomux) {
omap_cfg_reg(Y8_1610_MMC2_CMD);
omap_cfg_reg(Y10_1610_MMC2_CLK);
omap_cfg_reg(R18_1610_MMC2_CLKIN);
omap_cfg_reg(W8_1610_MMC2_DAT0);
if (mmc->wire4) {
omap_cfg_reg(V8_1610_MMC2_DAT1);
omap_cfg_reg(W15_1610_MMC2_DAT2);
omap_cfg_reg(R10_1610_MMC2_DAT3);
}
/* These are needed for the level shifter */
omap_cfg_reg(V9_1610_MMC2_CMDDIR);
omap_cfg_reg(V5_1610_MMC2_DATDIR0);
omap_cfg_reg(W19_1610_MMC2_DATDIR1);
}
/* Feedback clock must be set on OMAP-1710 MMC2 */
if (cpu_is_omap1710())
omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24),
MOD_CONF_CTRL_1);
mmc2_conf = *mmc;
(void) platform_device_register(&mmc_omap_device2);
}
#endif
return;
}
#else
static inline void omap_init_mmc(void) {}
#endif
/*-------------------------------------------------------------------------*/
/* Numbering for the SPI-capable controllers when used for SPI:
* spi = 1
* uwire = 2
* mmc1..2 = 3..4
* mcbsp1..3 = 5..7
*/
#if defined(CONFIG_SPI_OMAP_UWIRE) || defined(CONFIG_SPI_OMAP_UWIRE_MODULE)
#define OMAP_UWIRE_BASE 0xfffb3000
static struct resource uwire_resources[] = {
{
.start = OMAP_UWIRE_BASE,
.end = OMAP_UWIRE_BASE + 0x20,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device omap_uwire_device = {
.name = "omap_uwire",
.id = -1,
.num_resources = ARRAY_SIZE(uwire_resources),
.resource = uwire_resources,
};
static void omap_init_uwire(void)
{
/* FIXME define and use a boot tag; not all boards will be hooking
* up devices to the microwire controller, and multi-board configs
* mean that CONFIG_SPI_OMAP_UWIRE may be configured anyway...
*/
/* board-specific code must configure chipselects (only a few
* are normally used) and SCLK/SDI/SDO (each has two choices).
*/
(void) platform_device_register(&omap_uwire_device);
}
#else
static inline void omap_init_uwire(void) {}
#endif
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
#ifdef CONFIG_ARCH_OMAP24XX
#ifdef CONFIG_ARCH_OMAP2430
/* WDT2 */
#define OMAP_WDT_BASE 0x49016000
#else
#define OMAP_WDT_BASE 0x48022000
#endif
#else
#define OMAP_WDT_BASE 0xfffeb000
#endif
static struct resource wdt_resources[] = {
{
.start = OMAP_WDT_BASE,
.end = OMAP_WDT_BASE + 0x4f,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device omap_wdt_device = {
.name = "omap_wdt",
.id = -1,
.num_resources = ARRAY_SIZE(wdt_resources),
.resource = wdt_resources,
};
static void omap_init_wdt(void)
{
(void) platform_device_register(&omap_wdt_device);
}
#else
static inline void omap_init_wdt(void) {}
#endif
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_HW_RANDOM_OMAP) || defined(CONFIG_HW_RANDOM_OMAP_MODULE)
#ifdef CONFIG_ARCH_OMAP24XX
#define OMAP_RNG_BASE 0x480A0000
#else
#define OMAP_RNG_BASE 0xfffe5000
#endif
static struct resource rng_resources[] = {
{
.start = OMAP_RNG_BASE,
.end = OMAP_RNG_BASE + 0x4f,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device omap_rng_device = {
.name = "omap_rng",
.id = -1,
.num_resources = ARRAY_SIZE(rng_resources),
.resource = rng_resources,
};
static void omap_init_rng(void)
{
(void) platform_device_register(&omap_rng_device);
}
#else
static inline void omap_init_rng(void) {}
#endif
/*
* This gets called after board-specific INIT_MACHINE, and initializes most
* on-chip peripherals accessible on this board (except for few like USB):
*
* (a) Does any "standard config" pin muxing needed. Board-specific
* code will have muxed GPIO pins and done "nonstandard" setup;
* that code could live in the boot loader.
* (b) Populating board-specific platform_data with the data drivers
* rely on to handle wiring variations.
* (c) Creating platform devices as meaningful on this board and
* with this kernel configuration.
*
* Claiming GPIOs, and setting their direction and initial values, is the
* responsibility of the device drivers. So is responding to probe().
*
* Board-specific knowlege like creating devices or pin setup is to be
* kept out of drivers as much as possible. In particular, pin setup
* may be handled by the boot loader, and drivers should expect it will
* normally have been done by the time they're probed.
*/
static int __init omap_init_devices(void)
{
/* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
omap_init_dsp();
omap_init_kp();
omap_init_mmc();
omap_init_uwire();
omap_init_wdt();
omap_init_rng();
if (!cpu_is_omap2430() && !cpu_is_omap34xx()) {
omap_init_i2c();
}
return 0;
}
arch_initcall(omap_init_devices);
[-- Attachment #5: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* OMAP2430sdp MMC driver for 2.6.21
@ 2007-07-24 2:01 sree
2007-07-24 4:11 ` Syed Mohammed, Khasim
0 siblings, 1 reply; 8+ messages in thread
From: sree @ 2007-07-24 2:01 UTC (permalink / raw)
To: linux-omap-open-source
Hi
Regarding MMC/SD drivers
There is no need of porting the old TWL4030 drivers,
But I took the virtual Bus support from the 2.6.14 kernel
and able to read the data in SD card, and write the SD card with the new git
kernel
and my dmesg looks like
mmc0: starting CMD6 arg 00000002 flags 00000009
mmc0: set_ios: clock 400000Hz busmode 2 powermode 2 Vdd 14 Bus Width 2
MMC/SD card has been selected
mmc0: starting CMD16 arg 00000200 flags 00000009
mmc0: starting CMD16 arg 00000200 flags 00000009
<6>mmcblk0: mmc0:2199 SD512 500224KiB
<6> mmcblk0: mmcblk0:mmc0: starting CMD18 arg 00000000 flags 00000009
mmc0: starting CMD13 arg 21990000 flags 00000009
and I have to clean the driver and also I am having problem with the card
insertion and removal with the IRQ handling
the kernel crashes whenever I remove the card or Insert the card.I am
digging the problem
As soon as I do that I will get back again
the kernel crash :
PC is at queue_delayed_work+0x64/0xd8
PC is at queue_delayed_work+0x64/0xd8
LR is at 0xc1c67fe0
LR is at 0xc1c67fe0
pc : [<c004ed88>] lr : [<c1c67fe0>] Not tainted
sp : c0359f10 ip : c1c67fd0 fp : c0359f24
pc : [<c004ed88>] lr : [<c1c67fe0>] Not tainted
sp : c0359f10 ip : c1c67fd0 fp : c0359f24
r10: 00000000 r9 : 00000000 r8 : c033fda0
r10: 00000000 r9 : 00000000 r8 : c033fda0
r7 : c019d5b4 r6 : c0358000 r5 : 00000014 r4 : c0336960
r7 : c019d5b4 r6 : c0358000 r5 : 00000014 r4 : c0336960
r3 : c1c67fd4 r2 : 00000000 r1 : 00000000 r0 : c0336960
r3 : c1c67fd4 r2 : 00000000 r1 : 00000000 r0 : c0336960
Flags: nzcvFlags: nzcv IRQs on FIQs on Mode SVC_32 Segment kernel
IRQs on FIQs on Mode SVC_32 Segment kernel
Control: C5387F
Control: C5387F
Table: 8186C000 DAC: 00000017
Table: 8186C000 DAC: 00000017
Process events/0 (pid: 4, stack limit = 0xc0358248)
Process events/0 (pid: 4, stack limit = 0xc0358248)
Stack: (0xc0359f10 to 0xc035a000)
Stack: (0xc0359f10 to 0xc035a000)
It might be because of the different work scheduling in the new kernel
thanks
-sree
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: OMAP2430sdp MMC driver for 2.6.21
2007-07-24 2:01 sree
@ 2007-07-24 4:11 ` Syed Mohammed, Khasim
0 siblings, 0 replies; 8+ messages in thread
From: Syed Mohammed, Khasim @ 2007-07-24 4:11 UTC (permalink / raw)
To: sree, linux-omap-open-source
>and I have to clean the driver and also I am having problem with the card
>insertion and removal with the IRQ handling
>the kernel crashes whenever I remove the card or Insert the card.I am
>digging the problem
>As soon as I do that I will get back again
>
This is because of INIT_WORK in mmc driver,
In MMC detect function or where ever you are referring to schedule work use container_of, also note the parameter has changed to work_struct.
static void mmc_omap_detect(struct work_struct *work)
{
u16 vdd = 0;
struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, mmc_carddetect_work);
Otherwise you will be referring to wrong base address and so the crash.
Hope this helps.
Regards,
Khasim
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: OMAP2430sdp MMC driver for 2.6.21
@ 2007-07-25 17:13 石洋
2007-07-25 17:17 ` sree
0 siblings, 1 reply; 8+ messages in thread
From: 石洋 @ 2007-07-25 17:13 UTC (permalink / raw)
To: sreesamb; +Cc: linux-omap-open-sour...
Hi Sree,
I saw you enabled SD card successfully on OMAP2430sdp for 2.6.21 on linux-omap mailing list. Did you use the drivers posted by Khasim? Could you please share your patch or give me some hints? I also got the new git kernel, but I can't make SD card work well. I'm blocked here for two weeks. Following is my board's u-boot boot message:
U-Boot 1.1.4 (Sep 18 2006 - 16:46:43)
OMAP2430C-GP revision 3, PRCM #5A
TI 2430SDP 0.1 Version + mDDR (Boot NOR)
DRAM: 128 MB
Flash: 192 MB
Muxed OneNAND 128MB 1.8V 16-bit (0x30)
Scanning device for bad blocks
num of blocks = 2048
Bad eraseblock 120 at 0x00f00000
In: serial
Out: serial
Err: serial
OMAP243X SDP #
Thanks.
Best Regards,
Yang Shi
iPod、万 点 巨 额 点 卡、奖 学 金……海 量 奖 品,想 拿 就 拿!
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: OMAP2430sdp MMC driver for 2.6.21
2007-07-25 17:13 OMAP2430sdp MMC driver for 2.6.21 石洋
@ 2007-07-25 17:17 ` sree
2007-07-25 19:22 ` andrzej zaborowski
0 siblings, 1 reply; 8+ messages in thread
From: sree @ 2007-07-25 17:17 UTC (permalink / raw)
To: 石洋; +Cc: linux-omap-open-sour...
[-- Attachment #1: Type: text/plain, Size: 1267 bytes --]
Hi
I didnt used the patch sent by Khasim
I took the virtual Bus support from 2.6.14 kernel
and changed the mmc_2430sdp.c and omap_hsmmc.c as per the 2.6.21 kernel
I will send the patch whenever I finished cleaning it..
thanks
sree
On 7/25/07, 石洋 <shy828301@126.com> wrote:
>
> Hi Sree,
>
> I saw you enabled SD card successfully on OMAP2430sdp for 2.6.21 on
> linux-omap mailing list. Did you use the drivers posted by Khasim? Could you
> please share your patch or give me some hints? I also got the new git
> kernel, but I can't make SD card work well. I'm blocked here for two weeks.
> Following is my board's u-boot boot message:
>
> U-Boot 1.1.4 (Sep 18 2006 - 16:46:43)
>
> OMAP2430C-GP revision 3, PRCM #5A
> TI 2430SDP 0.1 Version + mDDR (Boot NOR)
> DRAM: 128 MB
> Flash: 192 MB
> Muxed OneNAND 128MB 1.8V 16-bit (0x30)
> Scanning device for bad blocks
> num of blocks = 2048
> Bad eraseblock 120 at 0x00f00000
> In: serial
> Out: serial
> Err: serial
> OMAP243X SDP #
>
> Thanks.
>
> Best Regards,
> Yang Shi
>
> ------------------------------
> iPod、万 点 巨 额 点 卡、奖 学 金……海 量 奖 品,想 拿 就 拿!
> <http://event.mail.163.com/chanel/xyq_07summer.htm?from=126_NO8>
--
Sreedhar Sambangi
MS in Electrical Engg
San Diego State University
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: OMAP2430sdp MMC driver for 2.6.21
2007-07-25 17:17 ` sree
@ 2007-07-25 19:22 ` andrzej zaborowski
2007-07-26 9:28 ` andrzej zaborowski
0 siblings, 1 reply; 8+ messages in thread
From: andrzej zaborowski @ 2007-07-25 19:22 UTC (permalink / raw)
To: linux-omap-open-sour...
Hi,
this may be unrelated but I found that the (not so) recent change in
mmc_omap_set_ios() broke SD support on OMAP310. I was digging into the
driver maybe two month sago and found that the change made the MMC
host send the init sequence to the card far too often during
initialisation. Sending it only once or reverting the following
commit:
http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-2.6.git;a=commitdiff;h=46a6730e3ff9add5089ddd007f998b97fb4e8571
made it work better. I haven't posted any information because I had to
give up before I managed to make the driver work completely, like it
did in 2.6.20. The issue of setting R1 response type instead of R6 and
other issues are still unresolved.
Regards
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: OMAP2430sdp MMC driver for 2.6.21
2007-07-25 19:22 ` andrzej zaborowski
@ 2007-07-26 9:28 ` andrzej zaborowski
0 siblings, 0 replies; 8+ messages in thread
From: andrzej zaborowski @ 2007-07-26 9:28 UTC (permalink / raw)
To: linux-omap-open-sour...
On 25/07/07, andrzej zaborowski <balrogg@gmail.com> wrote:
> Hi,
> this may be unrelated but I found that the (not so) recent change in
Sorry, this turns out to be completely unrelated to this thread.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2007-07-26 9:28 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-07-25 17:13 OMAP2430sdp MMC driver for 2.6.21 石洋
2007-07-25 17:17 ` sree
2007-07-25 19:22 ` andrzej zaborowski
2007-07-26 9:28 ` andrzej zaborowski
-- strict thread matches above, loose matches on Subject: below --
2007-07-24 2:01 sree
2007-07-24 4:11 ` Syed Mohammed, Khasim
2007-07-23 10:32 石洋
2007-07-23 22:04 ` Syed Mohammed, Khasim
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.