diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2010-10-12 21:31:38 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2010-10-12 21:31:38 +0200 |
commit | 23e13992c8dd993a69794952fdf4f1c11e3da6e4 (patch) | |
tree | ef8e13e993ad0553e45a3f182248d7f17b5ad502 /drivers | |
parent | 6af0fb083442de041012f4438b1f66cc24bf3c8f (diff) | |
parent | 869baba6581723842729bd3e83f1167431b0c317 (diff) | |
download | barebox-23e13992c8dd993a69794952fdf4f1c11e3da6e4.tar.gz barebox-23e13992c8dd993a69794952fdf4f1c11e3da6e4.tar.xz |
Merge branch 'mx51' into next
Conflicts:
arch/arm/Makefile
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Kconfig | 1 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/Kconfig | 16 | ||||
-rw-r--r-- | drivers/i2c/Makefile | 6 | ||||
-rw-r--r-- | drivers/i2c/mc13892.c | 164 | ||||
-rw-r--r-- | drivers/mci/Kconfig | 13 | ||||
-rw-r--r-- | drivers/mci/Makefile | 1 | ||||
-rw-r--r-- | drivers/mci/imx-esdhc.c | 512 | ||||
-rw-r--r-- | drivers/mci/imx-esdhc.h | 164 | ||||
-rw-r--r-- | drivers/mci/mci-core.c | 47 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 28 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 6 | ||||
-rw-r--r-- | drivers/mfd/lp3972.c (renamed from drivers/i2c/lp3972.c) | 0 | ||||
-rw-r--r-- | drivers/mfd/mc13783.c (renamed from drivers/spi/mc13783.c) | 0 | ||||
-rw-r--r-- | drivers/mfd/mc13892.c | 327 | ||||
-rw-r--r-- | drivers/mfd/mc34704.c (renamed from drivers/i2c/mc34704.c) | 2 | ||||
-rw-r--r-- | drivers/mfd/mc9sdz60.c (renamed from drivers/i2c/mc9sdz60.c) | 2 | ||||
-rw-r--r-- | drivers/mfd/twl4030.c (renamed from drivers/i2c/twl4030.c) | 2 | ||||
-rw-r--r-- | drivers/serial/serial_imx.c | 3 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 12 | ||||
-rw-r--r-- | drivers/spi/Makefile | 2 | ||||
-rw-r--r-- | drivers/spi/imx_spi.c | 347 | ||||
-rw-r--r-- | drivers/usb/host/ehci-omap.c | 2 | ||||
-rw-r--r-- | drivers/usb/otg/twl4030.c | 2 |
24 files changed, 1370 insertions, 290 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 13235f35f5..d94017bfc1 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -11,5 +11,6 @@ source "drivers/usb/Kconfig" source "drivers/video/Kconfig" source "drivers/mci/Kconfig" source "drivers/clk/Kconfig" +source "drivers/mfd/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 71d34f969b..242a564dd7 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_MCI) += mci/ obj-$(CONFIG_VIDEO) += video/ obj-y += clk/ +obj-y += mfd/ diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 9ce16558c4..c2af818393 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -5,20 +5,4 @@ if I2C source drivers/i2c/busses/Kconfig -config I2C_MC13892 - bool "MC13892 a.k.a. PMIC driver" - -config I2C_MC34704 - bool "MC34704 PMIC driver" - -config I2C_MC9SDZ60 - bool "MC9SDZ60 driver" - -config I2C_LP3972 - bool "LP3972 driver" - -config I2C_TWL4030 - bool "TWL4030 driver" - select GPIO - endif diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 0584b5589d..42e22c01b0 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -1,7 +1 @@ obj-$(CONFIG_I2C) += i2c.o busses/ - -obj-$(CONFIG_I2C_MC13892) += mc13892.o -obj-$(CONFIG_I2C_MC34704) += mc34704.o -obj-$(CONFIG_I2C_MC9SDZ60) += mc9sdz60.o -obj-$(CONFIG_I2C_LP3972) += lp3972.o -obj-$(CONFIG_I2C_TWL4030) += twl4030.o diff --git a/drivers/i2c/mc13892.c b/drivers/i2c/mc13892.c deleted file mode 100644 index 67d4232a23..0000000000 --- a/drivers/i2c/mc13892.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2007 Sascha Hauer, Pengutronix - * 2009 Marc Kleine-Budde <mkl@pengutronix.de> - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#include <common.h> -#include <init.h> -#include <driver.h> -#include <xfuncs.h> -#include <errno.h> - -#include <i2c/i2c.h> -#include <i2c/mc13892.h> - -#define DRIVERNAME "mc13892" - -#define to_mc13892(a) container_of(a, struct mc13892, cdev) - -static struct mc13892 *mc_dev; - -struct mc13892 *mc13892_get(void) -{ - if (!mc_dev) - return NULL; - - return mc_dev; -} -EXPORT_SYMBOL(mc13892_get); - -int mc13892_reg_read(struct mc13892 *mc13892, enum mc13892_reg reg, u32 *val) -{ - u8 buf[3]; - int ret; - - ret = i2c_read_reg(mc13892->client, reg, buf, 3); - *val = buf[0] << 16 | buf[1] << 8 | buf[2] << 0; - - return ret == 3 ? 0 : ret; -} -EXPORT_SYMBOL(mc13892_reg_read) - -int mc13892_reg_write(struct mc13892 *mc13892, enum mc13892_reg reg, u32 val) -{ - u8 buf[] = { - val >> 16, - val >> 8, - val >> 0, - }; - int ret; - - ret = i2c_write_reg(mc13892->client, reg, buf, 3); - - return ret == 3 ? 0 : ret; -} -EXPORT_SYMBOL(mc13892_reg_write) - -int mc13892_set_bits(struct mc13892 *mc13892, enum mc13892_reg reg, u32 mask, u32 val) -{ - u32 tmp; - int err; - - err = mc13892_reg_read(mc13892, reg, &tmp); - tmp = (tmp & ~mask) | val; - - if (!err) - err = mc13892_reg_write(mc13892, reg, tmp); - - return err; -} -EXPORT_SYMBOL(mc13892_set_bits); - -static ssize_t mc_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags) -{ - struct mc13892 *priv = to_mc13892(cdev); - u32 *buf = _buf; - size_t i = count >> 2; - int err; - - offset >>= 2; - - while (i) { - err = mc13892_reg_read(priv, offset, buf); - if (err) - return (ssize_t)err; - buf++; - i--; - offset++; - } - - return count; -} - -static ssize_t mc_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags) -{ - struct mc13892 *mc13892 = to_mc13892(cdev); - const u32 *buf = _buf; - size_t i = count >> 2; - int err; - - offset >>= 2; - - while (i) { - err = mc13892_reg_write(mc13892, offset, *buf); - if (err) - return (ssize_t)err; - buf++; - i--; - offset++; - } - - return count; -} - -static struct file_operations mc_fops = { - .lseek = dev_lseek_default, - .read = mc_read, - .write = mc_write, -}; - -static int mc_probe(struct device_d *dev) -{ - if (mc_dev) - return -EBUSY; - - mc_dev = xzalloc(sizeof(struct mc13892)); - mc_dev->cdev.name = DRIVERNAME; - mc_dev->client = to_i2c_client(dev); - mc_dev->cdev.size = 256; - mc_dev->cdev.dev = dev; - mc_dev->cdev.ops = &mc_fops; - - devfs_create(&mc_dev->cdev); - - return 0; -} - -static struct driver_d mc_driver = { - .name = DRIVERNAME, - .probe = mc_probe, -}; - -static int mc_init(void) -{ - register_driver(&mc_driver); - return 0; -} - -device_initcall(mc_init); diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig index 0bc4254acb..b1f2773354 100644 --- a/drivers/mci/Kconfig +++ b/drivers/mci/Kconfig @@ -48,4 +48,17 @@ config MCI_IMX Enable this entry to add support to read and write SD cards on a Freescale i.MX based system. +config MCI_IMX_ESDHC + bool "i.MX esdhc" + depends on ARCH_IMX25 || ARCH_IMX35 || ARCH_IMX51 + help + Enable this entry to add support to read and write SD cards on a + Freescale i.MX25/35/51 based system. + +config MCI_IMX_ESDHC_PIO + bool "use PIO mode" + depends on MCI_IMX_ESDHC + help + mostly useful for debugging. Normally you should use DMA. + endif diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile index f393e93b33..a10cb47960 100644 --- a/drivers/mci/Makefile +++ b/drivers/mci/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_MCI) += mci-core.o obj-$(CONFIG_MCI_STM378X) += stm378x.o obj-$(CONFIG_MCI_S3C) += s3c.o obj-$(CONFIG_MCI_IMX) += imx.o +obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c new file mode 100644 index 0000000000..63cd059f6d --- /dev/null +++ b/drivers/mci/imx-esdhc.c @@ -0,0 +1,512 @@ +/* + * Copyright 2007,2010 Freescale Semiconductor, Inc + * Andy Fleming + * + * Based vaguely on the pxa mmc code: + * (C) Copyright 2003 + * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> +#include <common.h> +#include <driver.h> +#include <init.h> +#include <malloc.h> +#include <mci.h> +#include <clock.h> +#include <asm/io.h> +#include <asm/mmu.h> +#include <mach/clock.h> + +#include "imx-esdhc.h" + +struct fsl_esdhc { + u32 dsaddr; + u32 blkattr; + u32 cmdarg; + u32 xfertyp; + u32 cmdrsp0; + u32 cmdrsp1; + u32 cmdrsp2; + u32 cmdrsp3; + u32 datport; + u32 prsstat; + u32 proctl; + u32 sysctl; + u32 irqstat; + u32 irqstaten; + u32 irqsigen; + u32 autoc12err; + u32 hostcapblt; + u32 wml; + char reserved1[8]; + u32 fevt; + char reserved2[168]; + u32 hostver; + char reserved3[780]; + u32 scr; +}; + +struct fsl_esdhc_host { + struct mci_host mci; + struct fsl_esdhc *regs; + u32 no_snoop; + unsigned long cur_clock; + struct device_d *dev; +}; + +#define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci) + +/* Return the XFERTYP flags for a given command and data packet */ +u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data) +{ + u32 xfertyp = 0; + + if (data) { + xfertyp |= XFERTYP_DPSEL; +#ifndef CONFIG_MCI_IMX_ESDHC_PIO + xfertyp |= XFERTYP_DMAEN; +#endif + if (data->blocks > 1) { + xfertyp |= XFERTYP_MSBSEL; + xfertyp |= XFERTYP_BCEN; + } + + if (data->flags & MMC_DATA_READ) + xfertyp |= XFERTYP_DTDSEL; + } + + if (cmd->resp_type & MMC_RSP_CRC) + xfertyp |= XFERTYP_CCCEN; + if (cmd->resp_type & MMC_RSP_OPCODE) + xfertyp |= XFERTYP_CICEN; + if (cmd->resp_type & MMC_RSP_136) + xfertyp |= XFERTYP_RSPTYP_136; + else if (cmd->resp_type & MMC_RSP_BUSY) + xfertyp |= XFERTYP_RSPTYP_48_BUSY; + else if (cmd->resp_type & MMC_RSP_PRESENT) + xfertyp |= XFERTYP_RSPTYP_48; + + return XFERTYP_CMD(cmd->cmdidx) | xfertyp; +} + +#ifdef CONFIG_MCI_IMX_ESDHC_PIO +/* + * PIO Read/Write Mode reduce the performace as DMA is not used in this mode. + */ +static void +esdhc_pio_read_write(struct mci_host *mci, struct mci_data *data) +{ + struct fsl_esdhc_host *host = to_fsl_esdhc(mci); + struct fsl_esdhc *regs = host->regs; + u32 blocks; + char *buffer; + u32 databuf; + u32 size; + u32 irqstat; + u32 timeout; + + if (data->flags & MMC_DATA_READ) { + blocks = data->blocks; + buffer = data->dest; + while (blocks) { + timeout = PIO_TIMEOUT; + size = data->blocksize; + irqstat = esdhc_read32(®s->irqstat); + while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BREN) + && --timeout); + if (timeout <= 0) { + printf("\nData Read Failed in PIO Mode."); + return; + } + while (size && (!(irqstat & IRQSTAT_TC))) { + udelay(100); /* Wait before last byte transfer complete */ + irqstat = esdhc_read32(®s->irqstat); + databuf = esdhc_read32(®s->datport); + *((u32 *)buffer) = databuf; + buffer += 4; + size -= 4; + } + blocks--; + } + } else { + blocks = data->blocks; + buffer = (char *)data->src; + while (blocks) { + timeout = PIO_TIMEOUT; + size = data->blocksize; + irqstat = esdhc_read32(®s->irqstat); + while (!(esdhc_read32(®s->prsstat) & PRSSTAT_BWEN) + && --timeout); + if (timeout <= 0) { + printf("\nData Write Failed in PIO Mode."); + return; + } + while (size && (!(irqstat & IRQSTAT_TC))) { + udelay(100); /* Wait before last byte transfer complete */ + databuf = *((u32 *)buffer); + buffer += 4; + size -= 4; + irqstat = esdhc_read32(®s->irqstat); + esdhc_write32(®s->datport, databuf); + } + blocks--; + } + } +} +#endif + +static int esdhc_setup_data(struct mci_host *mci, struct mci_data *data) +{ + struct fsl_esdhc_host *host = to_fsl_esdhc(mci); + struct fsl_esdhc *regs = host->regs; +#ifndef CONFIG_MCI_IMX_ESDHC_PIO + u32 wml_value; + + wml_value = data->blocksize/4; + + if (data->flags & MMC_DATA_READ) { + if (wml_value > 0x10) + wml_value = 0x10; + + esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); + esdhc_write32(®s->dsaddr, (u32)data->dest); + } else { + if (wml_value > 0x80) + wml_value = 0x80; + if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { + printf("\nThe SD card is locked. Can not write to a locked card.\n\n"); + return -ETIMEDOUT; + } + + esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, + wml_value << 16); + esdhc_write32(®s->dsaddr, (u32)data->src); + } +#else /* CONFIG_MCI_IMX_ESDHC_PIO */ + if (!(data->flags & MMC_DATA_READ)) { + if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { + printf("\nThe SD card is locked. " + "Can not write to a locked card.\n\n"); + return -ETIMEDOUT; + } + esdhc_write32(®s->dsaddr, (u32)data->src); + } else + esdhc_write32(®s->dsaddr, (u32)data->dest); +#endif /* CONFIG_MCI_IMX_ESDHC_PIO */ + + esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); + + return 0; +} + + +/* + * Sends a command out on the bus. Takes the mci pointer, + * a command pointer, and an optional data pointer. + */ +static int +esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) +{ + u32 xfertyp; + u32 irqstat; + struct fsl_esdhc_host *host = to_fsl_esdhc(mci); + struct fsl_esdhc *regs = host->regs; + + esdhc_write32(®s->irqstat, -1); + + /* Wait for the bus to be idle */ + while ((esdhc_read32(®s->prsstat) & PRSSTAT_CICHB) || + (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) + ; + + while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) + ; + + /* Wait at least 8 SD clock cycles before the next command */ + /* + * Note: This is way more than 8 cycles, but 1ms seems to + * resolve timing issues with some cards + */ + udelay(1000); + + /* Set up for a data transfer if we have one */ + if (data) { + int err; + + err = esdhc_setup_data(mci, data); + if(err) + return err; + if (data->flags & MMC_DATA_WRITE) { + dma_flush_range((unsigned long)data->src, + (unsigned long)(data->src + 512)); + } else + dma_clean_range((unsigned long)data->src, + (unsigned long)(data->src + 512)); + + } + + /* Figure out the transfer arguments */ + xfertyp = esdhc_xfertyp(cmd, data); + + /* Send the command */ + esdhc_write32(®s->cmdarg, cmd->cmdarg); + esdhc_write32(®s->xfertyp, xfertyp); + + /* Wait for the command to complete */ + while (!(esdhc_read32(®s->irqstat) & IRQSTAT_CC)) + ; + + irqstat = esdhc_read32(®s->irqstat); + esdhc_write32(®s->irqstat, irqstat); + + if (irqstat & CMD_ERR) + return -EIO; + + if (irqstat & IRQSTAT_CTOE) + return -ETIMEDOUT; + + /* Copy the response to the response buffer */ + if (cmd->resp_type & MMC_RSP_136) { + u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; + + cmdrsp3 = esdhc_read32(®s->cmdrsp3); + cmdrsp2 = esdhc_read32(®s->cmdrsp2); + cmdrsp1 = esdhc_read32(®s->cmdrsp1); + cmdrsp0 = esdhc_read32(®s->cmdrsp0); + cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); + cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); + cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); + cmd->response[3] = (cmdrsp0 << 8); + } else + cmd->response[0] = esdhc_read32(®s->cmdrsp0); + + /* Wait until all of the blocks are transferred */ + if (data) { +#ifdef CONFIG_MCI_IMX_ESDHC_PIO + esdhc_pio_read_write(mci, data); +#else + do { + irqstat = esdhc_read32(®s->irqstat); + + if (irqstat & DATA_ERR) + return -EIO; + + if (irqstat & IRQSTAT_DTOE) + return -ETIMEDOUT; + } while (!(irqstat & IRQSTAT_TC) && + (esdhc_read32(®s->prsstat) & PRSSTAT_DLA)); + + if (data->flags & MMC_DATA_READ) { + dma_inv_range((unsigned long)data->dest, + (unsigned long)(data->dest + 512)); + } +#endif + } + + esdhc_write32(®s->irqstat, -1); + + return 0; +} + +void set_sysctl(struct mci_host *mci, u32 clock) +{ + int div, pre_div; + struct fsl_esdhc_host *host = to_fsl_esdhc(mci); + struct fsl_esdhc *regs = host->regs; + int sdhc_clk = imx_get_mmcclk(); + u32 clk; + + if (clock < mci->f_min) + clock = mci->f_min; + + pre_div = 0; + + for (pre_div = 1; pre_div < 256; pre_div <<= 1) { + if (sdhc_clk / pre_div < clock * 16) + break; + }; + + div = sdhc_clk / pre_div / clock; + + if (sdhc_clk / pre_div / div > clock) + div++; + + host->cur_clock = sdhc_clk / pre_div / div; + + div -= 1; + pre_div >>= 1; + + dev_dbg(host->dev, "set clock: wanted: %d got: %d\n", clock, host->cur_clock); + dev_dbg(host->dev, "pre_div: %d div: %d\n", pre_div, div); + + clk = (pre_div << 8) | (div << 4); + + esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); + + esdhc_clrsetbits32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); + + udelay(10000); + + clk = SYSCTL_PEREN | SYSCTL_CKEN; + + esdhc_setbits32(®s->sysctl, clk); +} + +static void esdhc_set_ios(struct mci_host *mci, struct device_d *dev, + unsigned bus_width, unsigned clock) +{ + struct fsl_esdhc_host *host = to_fsl_esdhc(mci); + struct fsl_esdhc *regs = host->regs; + + /* Set the clock speed */ + set_sysctl(mci, clock); + + /* Set the bus width */ + esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); + + if (bus_width == 4) + esdhc_setbits32(®s->proctl, PROCTL_DTW_4); + else if (bus_width == 8) + esdhc_setbits32(®s->proctl, PROCTL_DTW_8); + +} + +static int esdhc_init(struct mci_host *mci, struct device_d *dev) +{ + struct fsl_esdhc_host *host = to_fsl_esdhc(mci); + struct fsl_esdhc *regs = host->regs; + int timeout = 1000; + int ret = 0; + + /* Enable cache snooping */ + if (host && !host->no_snoop) + esdhc_write32(®s->scr, 0x00000040); + + /* Reset the entire host controller */ + esdhc_write32(®s->sysctl, SYSCTL_RSTA); + + /* Wait until the controller is available */ + while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) + udelay(1000); + + esdhc_write32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); + + /* Set the initial clock speed */ + set_sysctl(mci, 400000); + + /* Disable the BRR and BWR bits in IRQSTAT */ + esdhc_clrbits32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); + + /* Put the PROCTL reg back to the default */ + esdhc_write32(®s->proctl, PROCTL_INIT); + + /* Set timout to the maximum value */ + esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); + + return ret; +} + +static int esdhc_reset(struct fsl_esdhc *regs) +{ + uint64_t start; + + /* reset the controller */ + esdhc_write32(®s->sysctl, SYSCTL_RSTA); + + start = get_time_ns(); + /* hardware clears the bit when it is done */ + while (1) { + if (!(esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) + break; + if (is_timeout(start, 100 * MSECOND)) { + printf("MMC/SD: Reset never completed.\n"); + return -EIO; + } + } + + return 0; +} + +static int fsl_esdhc_probe(struct device_d *dev) +{ + struct fsl_esdhc_host *host; + struct mci_host *mci; + u32 caps; + int ret; + + host = xzalloc(sizeof(*host)); + mci = &host->mci; + + host->dev = dev; + host->regs = (struct fsl_esdhc *)dev->map_base; + + /* First reset the eSDHC controller */ + ret = esdhc_reset(host->regs); + if (ret) { + free(host); + return ret; + } + + caps = esdhc_read32(&host->regs->hostcapblt); + + if (caps & ESDHC_HOSTCAPBLT_VS18) + mci->voltages |= MMC_VDD_165_195; + if (caps & ESDHC_HOSTCAPBLT_VS30) + mci->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31; + if (caps & ESDHC_HOSTCAPBLT_VS33) + mci->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34; + + mci->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT; + + if (caps & ESDHC_HOSTCAPBLT_HSS) + mci->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + + host->mci.send_cmd = esdhc_send_cmd; + host->mci.set_ios = esdhc_set_ios; + host->mci.init = esdhc_init; + host->mci.host_caps = MMC_MODE_4BIT; + + host->mci.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; + + host->mci.f_min = imx_get_mmcclk() >> 12; + if (host->mci.f_min < 200000) + host->mci.f_min = 200000; + host->mci.f_max = imx_get_mmcclk(); + + mci_register(&host->mci); + + return 0; +} + +static struct driver_d fsl_esdhc_driver = { + .name = "imx-esdhc", + .probe = fsl_esdhc_probe, +}; + +static int fsl_esdhc_init_driver(void) +{ + register_driver(&fsl_esdhc_driver); + return 0; +} + +device_initcall(fsl_esdhc_init_driver); + diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h new file mode 100644 index 0000000000..19fed5aebf --- /dev/null +++ b/drivers/mci/imx-esdhc.h @@ -0,0 +1,164 @@ +/* + * FSL SD/MMC Defines + *------------------------------------------------------------------- + * + * Copyright 2007-2008,2010 Freescale Semiconductor, Inc + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + *------------------------------------------------------------------- + * + */ + +#ifndef __FSL_ESDHC_H__ +#define __FSL_ESDHC_H__ + +#include <errno.h> +#include <asm/byteorder.h> + +/* FSL eSDHC-specific constants */ +#define SYSCTL 0x0002e02c +#define SYSCTL_INITA 0x08000000 +#define SYSCTL_TIMEOUT_MASK 0x000f0000 +#define SYSCTL_CLOCK_MASK 0x0000fff0 +#define SYSCTL_RSTA 0x01000000 +#define SYSCTL_CKEN 0x00000008 +#define SYSCTL_PEREN 0x00000004 +#define SYSCTL_HCKEN 0x00000002 +#define SYSCTL_IPGEN 0x00000001 +#define SYSCTL_RSTA 0x01000000 + +#define IRQSTAT 0x0002e030 +#define IRQSTAT_DMAE (0x10000000) +#define IRQSTAT_AC12E (0x01000000) +#define IRQSTAT_DEBE (0x00400000) +#define IRQSTAT_DCE (0x00200000) +#define IRQSTAT_DTOE (0x00100000) +#define IRQSTAT_CIE (0x00080000) +#define IRQSTAT_CEBE (0x00040000) +#define IRQSTAT_CCE (0x00020000) +#define IRQSTAT_CTOE (0x00010000) +#define IRQSTAT_CINT (0x00000100) +#define IRQSTAT_CRM (0x00000080) +#define IRQSTAT_CINS (0x00000040) +#define IRQSTAT_BRR (0x00000020) +#define IRQSTAT_BWR (0x00000010) +#define IRQSTAT_DINT (0x00000008) +#define IRQSTAT_BGE (0x00000004) +#define IRQSTAT_TC (0x00000002) +#define IRQSTAT_CC (0x00000001) + +#define CMD_ERR (IRQSTAT_CIE | IRQSTAT_CEBE | IRQSTAT_CCE) +#define DATA_ERR (IRQSTAT_DEBE | IRQSTAT_DCE | IRQSTAT_DTOE) + +#define IRQSTATEN 0x0002e034 +#define IRQSTATEN_DMAE (0x10000000) +#define IRQSTATEN_AC12E (0x01000000) +#define IRQSTATEN_DEBE (0x00400000) +#define IRQSTATEN_DCE (0x00200000) +#define IRQSTATEN_DTOE (0x00100000) +#define IRQSTATEN_CIE (0x00080000) +#define IRQSTATEN_CEBE (0x00040000) +#define IRQSTATEN_CCE (0x00020000) +#define IRQSTATEN_CTOE (0x00010000) +#define IRQSTATEN_CINT (0x00000100) +#define IRQSTATEN_CRM (0x00000080) +#define IRQSTATEN_CINS (0x00000040) +#define IRQSTATEN_BRR (0x00000020) +#define IRQSTATEN_BWR (0x00000010) +#define IRQSTATEN_DINT (0x00000008) +#define IRQSTATEN_BGE (0x00000004) +#define IRQSTATEN_TC (0x00000002) +#define IRQSTATEN_CC (0x00000001) + +#define PRSSTAT 0x0002e024 +#define PRSSTAT_CLSL (0x00800000) +#define PRSSTAT_WPSPL (0x00080000) +#define PRSSTAT_CDPL (0x00040000) +#define PRSSTAT_CINS (0x00010000) +#define PRSSTAT_BREN (0x00000800) +#define PRSSTAT_BWEN (0x00000400) +#define PRSSTAT_DLA (0x00000004) +#define PRSSTAT_CICHB (0x00000002) +#define PRSSTAT_CIDHB (0x00000001) + +#define PROCTL 0x0002e028 +#define PROCTL_INIT 0x00000020 +#define PROCTL_DTW_4 0x00000002 +#define PROCTL_DTW_8 0x00000004 + +#define CMDARG 0x0002e008 + +#define XFERTYP 0x0002e00c +#define XFERTYP_CMD(x) ((x & 0x3f) << 24) +#define XFERTYP_CMDTYP_NORMAL 0x0 +#define XFERTYP_CMDTYP_SUSPEND 0x00400000 +#define XFERTYP_CMDTYP_RESUME 0x00800000 +#define XFERTYP_CMDTYP_ABORT 0x00c00000 +#define XFERTYP_DPSEL 0x00200000 +#define XFERTYP_CICEN 0x00100000 +#define XFERTYP_CCCEN 0x00080000 +#define XFERTYP_RSPTYP_NONE 0 +#define XFERTYP_RSPTYP_136 0x00010000 +#define XFERTYP_RSPTYP_48 0x00020000 +#define XFERTYP_RSPTYP_48_BUSY 0x00030000 +#define XFERTYP_MSBSEL 0x00000020 +#define XFERTYP_DTDSEL 0x00000010 +#define XFERTYP_AC12EN 0x00000004 +#define XFERTYP_BCEN 0x00000002 +#define XFERTYP_DMAEN 0x00000001 + +#define CINS_TIMEOUT 1000 +#define PIO_TIMEOUT 100000 + +#define DSADDR 0x2e004 + +#define CMDRSP0 0x2e010 +#define CMDRSP1 0x2e014 +#define CMDRSP2 0x2e018 +#define CMDRSP3 0x2e01c + +#define DATPORT 0x2e020 + +#define WML 0x2e044 +#define WML_WRITE 0x00010000 +#define WML_RD_WML_MASK 0xff +#define WML_WR_WML_MASK 0xff0000 + +#define BLKATTR 0x2e004 +#define BLKATTR_CNT(x) ((x & 0xffff) << 16) +#define BLKATTR_SIZE(x) (x & 0x1fff) +#define MAX_BLK_CNT 0x7fff /* so malloc will have enough room with 32M */ + +#define ESDHC_HOSTCAPBLT_VS18 0x04000000 +#define ESDHC_HOSTCAPBLT_VS30 0x02000000 +#define ESDHC_HOSTCAPBLT_VS33 0x01000000 +#define ESDHC_HOSTCAPBLT_SRS 0x00800000 +#define ESDHC_HOSTCAPBLT_DMAS 0x00400000 +#define ESDHC_HOSTCAPBLT_HSS 0x00200000 + +struct fsl_esdhc_cfg { + u32 esdhc_base; + u32 no_snoop; +}; + +#define esdhc_read32(a) readl(a) +#define esdhc_write32(a, v) writel(v,a) +#define esdhc_clrsetbits32(a, c, s) writel((readl(a) & ~(c)) | (s), (a)) +#define esdhc_clrbits32(a, c) writel(readl(a) & ~(c), (a)) +#define esdhc_setbits32(a, s) writel(readl(a) | (s), (a)) + +#endif /* __FSL_ESDHC_H__ */ diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c index f961e46848..ea2706234a 100644 --- a/drivers/mci/mci-core.c +++ b/drivers/mci/mci-core.c @@ -45,7 +45,7 @@ * @brief Memory Card framework * * Checked with the following cards: - * - old Canon SD 16 MiB, does not like the 0x08 command (SD_CMD_SEND_IF_COND) -> failed + * - Canon MMC 16 MiB * - Kingston 512 MiB * - SanDisk 512 MiB * - Transcend SD Ultra, 1 GiB (Industrial) @@ -94,6 +94,8 @@ static int mci_set_blocklen(struct device_d *mci_dev, unsigned len) return mci_send_cmd(mci_dev, &cmd, NULL); } +static void *sector_buf; + /** * Write one block of data to the card * @param mci_dev MCI instance @@ -106,13 +108,21 @@ static int mci_block_write(struct device_d *mci_dev, const void *src, unsigned b struct mci *mci = GET_MCI_DATA(mci_dev); struct mci_cmd cmd; struct mci_data data; + const void *buf; + + if ((unsigned long)src & 0x3) { + memcpy(sector_buf, src, 512); + buf = sector_buf; + } else { + buf = src; + } mci_setup_cmd(&cmd, MMC_CMD_WRITE_SINGLE_BLOCK, mci->high_capacity != 0 ? blocknum : blocknum * mci->write_bl_len, MMC_RSP_R1); - data.src = src; + data.src = buf; data.blocks = 1; data.blocksize = mci->write_bl_len; data.flags = MMC_DATA_WRITE; @@ -927,7 +937,7 @@ static int mci_sd_write(struct device_d *disk_dev, uint64_t sector_start, } rc = mci_block_write(mci_dev, buffer, sector_start); if (rc != 0) { - pr_err("Writing block %u failed\n", (unsigned)sector_start); + pr_err("Writing block %u failed with %d\n", (unsigned)sector_start, rc); return rc; } sector_count--; @@ -973,7 +983,7 @@ static int mci_sd_read(struct device_d *disk_dev, uint64_t sector_start, } rc = mci_read_block(mci_dev, buffer, (unsigned)sector_start); if (rc != 0) { - pr_err("Reading block %lu failed\n", (unsigned)sector_start); + pr_err("Reading block %lu failed with %d\n", (unsigned)sector_start, rc); return rc; } sector_count--; @@ -1148,27 +1158,16 @@ static int mci_card_probe(struct device_d *mci_dev) /* Check if this card can handle the "SD Card Physical Layer Specification 2.0" */ rc = sd_send_if_cond(mci_dev); - if (rc) { + rc = sd_send_op_cond(mci_dev); + if (rc && rc == -ETIMEDOUT) { /* If the command timed out, we check for an MMC card */ - if (rc == -ETIMEDOUT) { - pr_debug("Card seems to be a MultiMediaCard\n"); - rc = mmc_send_op_cond(mci_dev); - if (rc) { - pr_err("MultiMediaCard did not respond to voltage select!\n"); - rc = -ENODEV; - goto on_error; - } - } else - goto on_error; - } else { - /* Its a 2.xx card. Setup operation conditions */ - rc = sd_send_op_cond(mci_dev); - if (rc) { - pr_debug("Cannot setup SD card's operation condition\n"); - goto on_error; - } + pr_debug("Card seems to be a MultiMediaCard\n"); + rc = mmc_send_op_cond(mci_dev); } + if (rc) + goto on_error; + rc = mci_startup(mci_dev); if (rc) { printf("Card's startup fails with %d\n", rc); @@ -1310,6 +1309,10 @@ static struct driver_d mci_driver = { static int mci_init(void) { + sector_buf = memalign(32, 512); + if (!sector_buf) + return -ENOMEM; + return register_driver(&mci_driver); } diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig new file mode 100644 index 0000000000..96440d852f --- /dev/null +++ b/drivers/mfd/Kconfig @@ -0,0 +1,28 @@ +menu MFD + +config I2C_MC13892 + depends on I2C || SPI + bool "MC13892 a.k.a. PMIC driver" + +config I2C_MC34704 + depends on I2C + bool "MC34704 PMIC driver" + +config I2C_MC9SDZ60 + depends on I2C + bool "MC9SDZ60 driver" + +config I2C_LP3972 + depends on I2C + bool "LP3972 driver" + +config I2C_TWL4030 + depends on I2C + bool "TWL4030 driver" + select GPIO + +config DRIVER_SPI_MC13783 + depends on SPI + bool "MC13783 a.k.a. PMIC driver" + +endmenu diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile new file mode 100644 index 0000000000..d411f23b69 --- /dev/null +++ b/drivers/mfd/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_I2C_MC13892) += mc13892.o +obj-$(CONFIG_I2C_MC34704) += mc34704.o +obj-$(CONFIG_I2C_MC9SDZ60) += mc9sdz60.o +obj-$(CONFIG_I2C_LP3972) += lp3972.o +obj-$(CONFIG_I2C_TWL4030) += twl4030.o +obj-$(CONFIG_DRIVER_SPI_MC13783) += mc13783.o diff --git a/drivers/i2c/lp3972.c b/drivers/mfd/lp3972.c index 98266990dc..98266990dc 100644 --- a/drivers/i2c/lp3972.c +++ b/drivers/mfd/lp3972.c diff --git a/drivers/spi/mc13783.c b/drivers/mfd/mc13783.c index 19e2780920..19e2780920 100644 --- a/drivers/spi/mc13783.c +++ b/drivers/mfd/mc13783.c diff --git a/drivers/mfd/mc13892.c b/drivers/mfd/mc13892.c new file mode 100644 index 0000000000..08a439b4c7 --- /dev/null +++ b/drivers/mfd/mc13892.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2007 Sascha Hauer, Pengutronix + * 2009 Marc Kleine-Budde <mkl@pengutronix.de> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <init.h> +#include <driver.h> +#include <xfuncs.h> +#include <errno.h> +#include <spi/spi.h> +#include <malloc.h> + +#include <i2c/i2c.h> +#include <mfd/mc13892.h> + +#define DRIVERNAME "mc13892" + +#define to_mc13892(a) container_of(a, struct mc13892, cdev) + +static struct mc13892 *mc_dev; + +struct mc13892 *mc13892_get(void) +{ + if (!mc_dev) + return NULL; + + return mc_dev; +} +EXPORT_SYMBOL(mc13892_get); + +#ifdef CONFIG_SPI +static int spi_rw(struct spi_device *spi, void * buf, size_t len) +{ + int ret; + + struct spi_transfer t = { + .tx_buf = (const void *)buf, + .rx_buf = buf, + .len = len, + .cs_change = 0, + .delay_usecs = 0, + }; + struct spi_message m; + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + if ((ret = spi_sync(spi, &m))) + return ret; + return 0; +} + +#define MXC_PMIC_REG_NUM(reg) (((reg) & 0x3f) << 25) +#define MXC_PMIC_WRITE (1 << 31) + +static int mc13892_spi_reg_read(struct mc13892 *mc13892, enum mc13892_reg reg, u32 *val) +{ + uint32_t buf; + + buf = MXC_PMIC_REG_NUM(reg); + + spi_rw(mc13892->spi, &buf, 4); + + *val = buf; + + return 0; +} + +static int mc13892_spi_reg_write(struct mc13892 *mc13892, enum mc13892_reg reg, u32 val) +{ + uint32_t buf = MXC_PMIC_REG_NUM(reg) | MXC_PMIC_WRITE | (val & 0xffffff); + + spi_rw(mc13892->spi, &buf, 4); + + return 0; +} +#endif + +#ifdef CONFIG_I2C +static int mc13892_i2c_reg_read(struct mc13892 *mc13892, enum mc13892_reg reg, u32 *val) +{ + u8 buf[3]; + int ret; + + ret = i2c_read_reg(mc13892->client, reg, buf, 3); + *val = buf[0] << 16 | buf[1] << 8 | buf[2] << 0; + + return ret == 3 ? 0 : ret; +} + +static int mc13892_i2c_reg_write(struct mc13892 *mc13892, enum mc13892_reg reg, u32 val) +{ + u8 buf[] = { + val >> 16, + val >> 8, + val >> 0, + }; + int ret; + + ret = i2c_write_reg(mc13892->client, reg, buf, 3); + + return ret == 3 ? 0 : ret; +} +#endif + +int mc13892_reg_write(struct mc13892 *mc13892, enum mc13892_reg reg, u32 val) +{ +#ifdef CONFIG_I2C + if (mc13892->mode == MC13892_MODE_I2C) + return mc13892_i2c_reg_write(mc13892, reg, val); +#endif +#ifdef CONFIG_SPI + if (mc13892->mode == MC13892_MODE_SPI) + return mc13892_spi_reg_write(mc13892, reg, val); +#endif + return -EINVAL; +} +EXPORT_SYMBOL(mc13892_reg_write) + +int mc13892_reg_read(struct mc13892 *mc13892, enum mc13892_reg reg, u32 *val) +{ +#ifdef CONFIG_I2C + if (mc13892->mode == MC13892_MODE_I2C) + return mc13892_i2c_reg_read(mc13892, reg, val); +#endif +#ifdef CONFIG_SPI + if (mc13892->mode == MC13892_MODE_SPI) + return mc13892_spi_reg_read(mc13892, reg, val); +#endif + return -EINVAL; +} +EXPORT_SYMBOL(mc13892_reg_read) + +int mc13892_set_bits(struct mc13892 *mc13892, enum mc13892_reg reg, u32 mask, u32 val) +{ + u32 tmp; + int err; + + err = mc13892_reg_read(mc13892, reg, &tmp); + tmp = (tmp & ~mask) | val; + + if (!err) + err = mc13892_reg_write(mc13892, reg, tmp); + + return err; +} +EXPORT_SYMBOL(mc13892_set_bits); + +static ssize_t mc_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags) +{ + struct mc13892 *priv = to_mc13892(cdev); + u32 *buf = _buf; + size_t i = count >> 2; + int err; + + offset >>= 2; + + while (i) { + err = mc13892_reg_read(priv, offset, buf); + if (err) + return (ssize_t)err; + buf++; + i--; + offset++; + } + + return count; +} + +static ssize_t mc_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags) +{ + struct mc13892 *mc13892 = to_mc13892(cdev); + const u32 *buf = _buf; + size_t i = count >> 2; + int err; + + offset >>= 2; + + while (i) { + err = mc13892_reg_write(mc13892, offset, *buf); + if (err) + return (ssize_t)err; + buf++; + i--; + offset++; + } + + return count; +} + +static struct file_operations mc_fops = { + .lseek = dev_lseek_default, + .read = mc_read, + .write = mc_write, +}; + +struct mc13892_rev { + u16 rev_id; + enum mc13892_revision rev; + char *revstr; +}; + +static struct mc13892_rev mc13892_revisions[] = { + { 0x01, MC13892_REVISION_1_0, "1.0" }, + { 0x09, MC13892_REVISION_1_1, "1.1" }, + { 0x0a, MC13892_REVISION_1_2, "1.2" }, + { 0x10, MC13892_REVISION_2_0, "2.0" }, + { 0x11, MC13892_REVISION_2_1, "2.1" }, + { 0x18, MC13892_REVISION_3_0, "3.0" }, + { 0x19, MC13892_REVISION_3_1, "3.1" }, + { 0x1a, MC13892_REVISION_3_2, "3.2" }, + { 0x02, MC13892_REVISION_3_2a, "3.2a" }, + { 0x1b, MC13892_REVISION_3_3, "3.3" }, + { 0x1d, MC13892_REVISION_3_5, "3.5" }, +}; + +static int mc13893_query_revision(struct mc13892 *mc13892) +{ + unsigned int rev_id; + char *revstr; + int rev, i; + + mc13892_reg_read(mc13892, 7, &rev_id); + + for (i = 0; i < ARRAY_SIZE(mc13892_revisions); i++) + if ((rev_id & 0x1f) == mc13892_revisions[i].rev_id) + break; + + if (i == ARRAY_SIZE(mc13892_revisions)) + return -EINVAL; + + rev = mc13892_revisions[i].rev; + revstr = mc13892_revisions[i].revstr; + + if (rev == MC13892_REVISION_2_0) { + if ((rev_id >> 9) & 0x3) { + rev = MC13892_REVISION_2_0a; + revstr = "2.0a"; + } + } + + dev_info(mc_dev->cdev.dev, "PMIC ID: 0x%08x [Rev: %s]\n", + rev_id, revstr); + + mc13892->revision = rev; + + return rev; +} + +static int mc_probe(struct device_d *dev, enum mc13892_mode mode) +{ + int rev; + + if (mc_dev) + return -EBUSY; + + mc_dev = xzalloc(sizeof(struct mc13892)); + mc_dev->mode = mode; + mc_dev->cdev.name = DRIVERNAME; + if (mode == MC13892_MODE_I2C) { + mc_dev->client = to_i2c_client(dev); + } + if (mode == MC13892_MODE_SPI) { + mc_dev->spi = dev->type_data; + mc_dev->spi->mode = SPI_MODE_0 | SPI_CS_HIGH; + mc_dev->spi->bits_per_word = 32; + } + mc_dev->cdev.size = 256; + mc_dev->cdev.dev = dev; + mc_dev->cdev.ops = &mc_fops; + + rev = mc13893_query_revision(mc_dev); + if (rev < 0) { + free(mc_dev); + return -EINVAL; + } + + devfs_create(&mc_dev->cdev); + + return 0; +} + +static int mc_i2c_probe(struct device_d *dev) +{ + return mc_probe(dev, MC13892_MODE_I2C); +} + +static int mc_spi_probe(struct device_d *dev) +{ + return mc_probe(dev, MC13892_MODE_SPI); +} + +static struct driver_d mc_i2c_driver = { + .name = "mc13892-i2c", + .probe = mc_i2c_probe, +}; + +static struct driver_d mc_spi_driver = { + .name = "mc13892-spi", + .probe = mc_spi_probe, +}; + +static int mc_init(void) +{ + register_driver(&mc_i2c_driver); + register_driver(&mc_spi_driver); + return 0; +} + +device_initcall(mc_init); diff --git a/drivers/i2c/mc34704.c b/drivers/mfd/mc34704.c index 51a8737209..a2171b35d1 100644 --- a/drivers/i2c/mc34704.c +++ b/drivers/mfd/mc34704.c @@ -27,7 +27,7 @@ #include <errno.h> #include <i2c/i2c.h> -#include <i2c/mc34704.h> +#include <mfd/mc34704.h> #define DRIVERNAME "mc34704" diff --git a/drivers/i2c/mc9sdz60.c b/drivers/mfd/mc9sdz60.c index 3580af8852..db208ec2db 100644 --- a/drivers/i2c/mc9sdz60.c +++ b/drivers/mfd/mc9sdz60.c @@ -26,7 +26,7 @@ #include <errno.h> #include <i2c/i2c.h> -#include <i2c/mc9sdz60.h> +#include <mfd/mc9sdz60.h> #define DRIVERNAME "mc9sdz60" diff --git a/drivers/i2c/twl4030.c b/drivers/mfd/twl4030.c index 5305ec67e3..81bf48bbb7 100644 --- a/drivers/i2c/twl4030.c +++ b/drivers/mfd/twl4030.c @@ -12,7 +12,7 @@ #include <errno.h> #include <i2c/i2c.h> -#include <i2c/twl4030.h> +#include <mfd/twl4030.h> #define DRIVERNAME "twl4030" diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c index 801004e186..25e6a0c6fc 100644 --- a/drivers/serial/serial_imx.c +++ b/drivers/serial/serial_imx.c @@ -160,7 +160,8 @@ # define UCR3_VAL (0x700 | UCR3_RXDMUXSEL) # define UCR4_VAL UCR4_CTSTL_32 #endif -#if defined CONFIG_ARCH_IMX31 || defined CONFIG_ARCH_IMX35 || defined CONFIG_ARCH_IMX25 +#if defined CONFIG_ARCH_IMX31 || defined CONFIG_ARCH_IMX35 || \ + defined CONFIG_ARCH_IMX25 || defined CONFIG_ARCH_IMX51 # define UCR1_VAL (0) # define UCR3_VAL (0x700 | UCR3_RXDMUXSEL) # define UCR4_VAL UCR4_CTSTL_32 diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 3eebd08983..a88e179e5a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -9,8 +9,14 @@ config DRIVER_SPI_IMX depends on ARCH_IMX depends on SPI -config DRIVER_SPI_MC13783 - bool "MC13783 a.k.a. PMIC driver" - depends on SPI +config DRIVER_SPI_IMX_0_0 + bool + depends on ARCH_IMX27 + default y + +config DRIVER_SPI_IMX_2_3 + bool + depends on ARCH_IMX51 + default y endmenu diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 81f2c6bc62..b2b2f6788f 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -1,4 +1,2 @@ obj-$(CONFIG_SPI) += spi.o obj-$(CONFIG_DRIVER_SPI_IMX) += imx_spi.o - -obj-$(CONFIG_DRIVER_SPI_MC13783) += mc13783.o diff --git a/drivers/spi/imx_spi.c b/drivers/spi/imx_spi.c index 5c9791978a..2ad1bfa499 100644 --- a/drivers/spi/imx_spi.c +++ b/drivers/spi/imx_spi.c @@ -26,47 +26,104 @@ #include <asm/io.h> #include <gpio.h> #include <mach/spi.h> - -#define MXC_CSPIRXDATA 0x00 -#define MXC_CSPITXDATA 0x04 -#define MXC_CSPICTRL 0x08 -#define MXC_CSPIINT 0x0C -#define MXC_CSPIDMA 0x18 -#define MXC_CSPISTAT 0x0C -#define MXC_CSPIPERIOD 0x14 -#define MXC_CSPITEST 0x10 -#define MXC_CSPIRESET 0x1C - -#define MXC_CSPICTRL_ENABLE (1 << 10) -#define MXC_CSPICTRL_MASTER (1 << 11) -#define MXC_CSPICTRL_XCH (1 << 9) -#define MXC_CSPICTRL_LOWPOL (1 << 5) -#define MXC_CSPICTRL_PHA (1 << 6) -#define MXC_CSPICTRL_SSCTL (1 << 7) -#define MXC_CSPICTRL_HIGHSSPOL (1 << 8) -#define MXC_CSPICTRL_CS(x) (((x) & 0x3) << 19) -#define MXC_CSPICTRL_BITCOUNT(x) (((x) & 0x1f) << 0) -#define MXC_CSPICTRL_DATARATE(x) (((x) & 0x7) << 14) - -#define MXC_CSPICTRL_MAXDATRATE 0x10 -#define MXC_CSPICTRL_DATAMASK 0x1F -#define MXC_CSPICTRL_DATASHIFT 14 - -#define MXC_CSPISTAT_TE (1 << 0) -#define MXC_CSPISTAT_TH (1 << 1) -#define MXC_CSPISTAT_TF (1 << 2) -#define MXC_CSPISTAT_RR (1 << 4) -#define MXC_CSPISTAT_RH (1 << 5) -#define MXC_CSPISTAT_RF (1 << 6) -#define MXC_CSPISTAT_RO (1 << 7) - -#define MXC_CSPIPERIOD_32KHZ (1 << 15) - -#define MXC_CSPITEST_LBC (1 << 14) +#include <mach/generic.h> + +#define CSPI_0_0_RXDATA 0x00 +#define CSPI_0_0_TXDATA 0x04 +#define CSPI_0_0_CTRL 0x08 +#define CSPI_0_0_INT 0x0C +#define CSPI_0_0_DMA 0x18 +#define CSPI_0_0_STAT 0x0C +#define CSPI_0_0_PERIOD 0x14 +#define CSPI_0_0_TEST 0x10 +#define CSPI_0_0_RESET 0x1C + +#define CSPI_0_0_CTRL_ENABLE (1 << 10) +#define CSPI_0_0_CTRL_MASTER (1 << 11) +#define CSPI_0_0_CTRL_XCH (1 << 9) +#define CSPI_0_0_CTRL_LOWPOL (1 << 5) +#define CSPI_0_0_CTRL_PHA (1 << 6) +#define CSPI_0_0_CTRL_SSCTL (1 << 7) +#define CSPI_0_0_CTRL_HIGHSSPOL (1 << 8) +#define CSPI_0_0_CTRL_CS(x) (((x) & 0x3) << 19) +#define CSPI_0_0_CTRL_BITCOUNT(x) (((x) & 0x1f) << 0) +#define CSPI_0_0_CTRL_DATARATE(x) (((x) & 0x7) << 14) + +#define CSPI_0_0_CTRL_MAXDATRATE 0x10 +#define CSPI_0_0_CTRL_DATAMASK 0x1F +#define CSPI_0_0_CTRL_DATASHIFT 14 + +#define CSPI_0_0_STAT_TE (1 << 0) +#define CSPI_0_0_STAT_TH (1 << 1) +#define CSPI_0_0_STAT_TF (1 << 2) +#define CSPI_0_0_STAT_RR (1 << 4) +#define CSPI_0_0_STAT_RH (1 << 5) +#define CSPI_0_0_STAT_RF (1 << 6) +#define CSPI_0_0_STAT_RO (1 << 7) + +#define CSPI_0_0_PERIOD_32KHZ (1 << 15) + +#define CSPI_0_0_TEST_LBC (1 << 14) + +#define CSPI_2_3_RXDATA 0x00 +#define CSPI_2_3_TXDATA 0x04 +#define CSPI_2_3_CTRL 0x08 +#define CSPI_2_3_CTRL_ENABLE (1 << 0) +#define CSPI_2_3_CTRL_XCH (1 << 2) +#define CSPI_2_3_CTRL_MODE(cs) (1 << ((cs) + 4)) +#define CSPI_2_3_CTRL_POSTDIV_OFFSET 8 +#define CSPI_2_3_CTRL_PREDIV_OFFSET 12 +#define CSPI_2_3_CTRL_CS(cs) ((cs) << 18) +#define CSPI_2_3_CTRL_BL_OFFSET 20 + +#define CSPI_2_3_CONFIG 0x0c +#define CSPI_2_3_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0)) +#define CSPI_2_3_CONFIG_SCLKPOL(cs) (1 << ((cs) + 4)) +#define CSPI_2_3_CONFIG_SBBCTRL(cs) (1 << ((cs) + 8)) +#define CSPI_2_3_CONFIG_SSBPOL(cs) (1 << ((cs) + 12)) + +#define CSPI_2_3_INT 0x10 +#define CSPI_2_3_INT_TEEN (1 << 0) +#define CSPI_2_3_INT_RREN (1 << 3) + +#define CSPI_2_3_STAT 0x18 +#define CSPI_2_3_STAT_RR (1 << 3) + +enum imx_spi_devtype { +#ifdef CONFIG_DRIVER_SPI_IMX1 + SPI_IMX_VER_IMX1, +#endif +#ifdef CONFIG_DRIVER_SPI_IMX_0_0 + SPI_IMX_VER_0_0, +#endif +#ifdef CONFIG_DRIVER_SPI_IMX_0_4 + SPI_IMX_VER_0_4, +#endif +#ifdef CONFIG_DRIVER_SPI_IMX_0_5 + SPI_IMX_VER_0_5, +#endif +#ifdef CONFIG_DRIVER_SPI_IMX_0_7 + SPI_IMX_VER_0_7, +#endif +#ifdef CONFIG_DRIVER_SPI_IMX_2_3 + SPI_IMX_VER_2_3, +#endif +}; struct imx_spi { - struct spi_master master; - int *chipselect; + struct spi_master master; + int *cs_array; + void __iomem *regs; + + unsigned int (*xchg_single)(struct imx_spi *imx, u32 data); + void (*chipselect)(struct spi_device *spi, int active); + void (*init)(struct imx_spi *imx); +}; + +struct spi_imx_devtype_data { + unsigned int (*xchg_single)(struct imx_spi *imx, u32 data); + void (*chipselect)(struct spi_device *spi, int active); + void (*init)(struct imx_spi *imx); }; static int imx_spi_setup(struct spi_device *spi) @@ -77,29 +134,31 @@ static int imx_spi_setup(struct spi_device *spi) return 0; } -static unsigned int spi_xchg_single(ulong base, unsigned int data) +#ifdef CONFIG_DRIVER_SPI_IMX_0_0 +static unsigned int cspi_0_0_xchg_single(struct imx_spi *imx, unsigned int data) { + void __iomem *base = imx->regs; - unsigned int cfg_reg = readl(base + MXC_CSPICTRL); + unsigned int cfg_reg = readl(base + CSPI_0_0_CTRL); - writel(data, base + MXC_CSPITXDATA); + writel(data, base + CSPI_0_0_TXDATA); - cfg_reg |= MXC_CSPICTRL_XCH; + cfg_reg |= CSPI_0_0_CTRL_XCH; - writel(cfg_reg, base + MXC_CSPICTRL); + writel(cfg_reg, base + CSPI_0_0_CTRL); - while (!(readl(base + MXC_CSPIINT) & MXC_CSPISTAT_RR)); + while (!(readl(base + CSPI_0_0_INT) & CSPI_0_0_STAT_RR)); - return readl(base + MXC_CSPIRXDATA); + return readl(base + CSPI_0_0_RXDATA); } -static void mxc_spi_chipselect(struct spi_device *spi, int is_active) +static void cspi_0_0_chipselect(struct spi_device *spi, int is_active) { struct spi_master *master = spi->master; struct imx_spi *imx = container_of(master, struct imx_spi, master); - ulong base = master->dev->map_base; + void __iomem *base = imx->regs; unsigned int cs = 0; - int gpio = imx->chipselect[spi->chip_select]; + int gpio = imx->cs_array[spi->chip_select]; u32 ctrl_reg; if (spi->mode & SPI_CS_HIGH) @@ -111,35 +170,156 @@ static void mxc_spi_chipselect(struct spi_device *spi, int is_active) return; } - ctrl_reg = MXC_CSPICTRL_BITCOUNT(spi->bits_per_word - 1) - | MXC_CSPICTRL_DATARATE(7) /* FIXME: calculate data rate */ - | MXC_CSPICTRL_ENABLE - | MXC_CSPICTRL_MASTER; + ctrl_reg = CSPI_0_0_CTRL_BITCOUNT(spi->bits_per_word - 1) + | CSPI_0_0_CTRL_DATARATE(7) /* FIXME: calculate data rate */ + | CSPI_0_0_CTRL_ENABLE + | CSPI_0_0_CTRL_MASTER; if (gpio < 0) { - ctrl_reg |= MXC_CSPICTRL_CS(gpio + 32); + ctrl_reg |= CSPI_0_0_CTRL_CS(gpio + 32); } if (spi->mode & SPI_CPHA) - ctrl_reg |= MXC_CSPICTRL_PHA; + ctrl_reg |= CSPI_0_0_CTRL_PHA; if (spi->mode & SPI_CPOL) - ctrl_reg |= MXC_CSPICTRL_LOWPOL; + ctrl_reg |= CSPI_0_0_CTRL_LOWPOL; if (spi->mode & SPI_CS_HIGH) - ctrl_reg |= MXC_CSPICTRL_HIGHSSPOL; + ctrl_reg |= CSPI_0_0_CTRL_HIGHSSPOL; - writel(ctrl_reg, base + MXC_CSPICTRL); + writel(ctrl_reg, base + CSPI_0_0_CTRL); if (gpio >= 0) gpio_set_value(gpio, cs); } +static void cspi_0_0_init(struct imx_spi *imx) +{ + void __iomem *base = imx->regs; + + writel(CSPI_0_0_CTRL_ENABLE | CSPI_0_0_CTRL_MASTER, + base + CSPI_0_0_CTRL); + writel(CSPI_0_0_PERIOD_32KHZ, + base + CSPI_0_0_PERIOD); + while (readl(base + CSPI_0_0_INT) & CSPI_0_0_STAT_RR) + readl(base + CSPI_0_0_RXDATA); + writel(0, base + CSPI_0_0_INT); +} +#endif + +#ifdef CONFIG_DRIVER_SPI_IMX_2_3 +static unsigned int cspi_2_3_xchg_single(struct imx_spi *imx, unsigned int data) +{ + void __iomem *base = imx->regs; + + unsigned int cfg_reg = readl(base + CSPI_2_3_CTRL); + + writel(data, base + CSPI_2_3_TXDATA); + + cfg_reg |= CSPI_2_3_CTRL_XCH; + + writel(cfg_reg, base + CSPI_2_3_CTRL); + + while (!(readl(base + CSPI_2_3_STAT) & CSPI_2_3_STAT_RR)); + + return readl(base + CSPI_2_3_RXDATA); +} + +/* FIXME: include/linux/kernel.h */ +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) + +static unsigned int cspi_2_3_clkdiv(unsigned int fin, unsigned int fspi) +{ + /* + * there are two 4-bit dividers, the pre-divider divides by + * $pre, the post-divider by 2^$post + */ + unsigned int pre, post; + + if (unlikely(fspi > fin)) + return 0; + + post = fls(fin) - fls(fspi); + if (fin > fspi << post) + post++; + + /* now we have: (fin <= fspi << post) with post being minimal */ + + post = max(4U, post) - 4; + if (unlikely(post > 0xf)) { + pr_err("%s: cannot set clock freq: %u (base freq: %u)\n", + __func__, fspi, fin); + return 0xff; + } + + pre = DIV_ROUND_UP(fin, fspi << post) - 1; + + pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n", + __func__, fin, fspi, post, pre); + return (pre << CSPI_2_3_CTRL_PREDIV_OFFSET) | + (post << CSPI_2_3_CTRL_POSTDIV_OFFSET); +} + +static void cspi_2_3_chipselect(struct spi_device *spi, int is_active) +{ + struct spi_master *master = spi->master; + struct imx_spi *imx = container_of(master, struct imx_spi, master); + void __iomem *base = imx->regs; + unsigned int cs = spi->chip_select, gpio_cs = 0; + int gpio = imx->cs_array[spi->chip_select]; + u32 ctrl, cfg = 0; + + if (spi->mode & SPI_CS_HIGH) + gpio_cs = 1; + + if (!is_active) { + if (gpio >= 0) + gpio_set_value(gpio, !gpio_cs); + return; + } + + ctrl = CSPI_2_3_CTRL_ENABLE; + + /* set master mode */ + ctrl |= CSPI_2_3_CTRL_MODE(cs); + + /* set clock speed */ + ctrl |= cspi_2_3_clkdiv(166000000, spi->max_speed_hz); + + /* set chip select to use */ + ctrl |= CSPI_2_3_CTRL_CS(cs); + + ctrl |= (spi->bits_per_word - 1) << CSPI_2_3_CTRL_BL_OFFSET; + + cfg |= CSPI_2_3_CONFIG_SBBCTRL(cs); + + if (spi->mode & SPI_CPHA) + cfg |= CSPI_2_3_CONFIG_SCLKPHA(cs); + + if (spi->mode & SPI_CPOL) + cfg |= CSPI_2_3_CONFIG_SCLKPOL(cs); + + if (spi->mode & SPI_CS_HIGH) + cfg |= CSPI_2_3_CONFIG_SSBPOL(cs); + + writel(ctrl, base + CSPI_2_3_CTRL); + writel(cfg, base + CSPI_2_3_CONFIG); + + if (gpio >= 0) + gpio_set_value(gpio, gpio_cs); +} + +static void cspi_2_3_init(struct imx_spi *imx) +{ +} +#endif + static int imx_spi_transfer(struct spi_device *spi, struct spi_message *mesg) { struct spi_master *master = spi->master; - ulong base = master->dev->map_base; + struct imx_spi *imx = container_of(master, struct imx_spi, master); struct spi_transfer *t = NULL; - mxc_spi_chipselect(spi, 1); + imx->chipselect(spi, 1); list_for_each_entry (t, &mesg->transfers, transfer_list) { const u32 *txbuf = t->tx_buf; @@ -147,21 +327,39 @@ static int imx_spi_transfer(struct spi_device *spi, struct spi_message *mesg) int i = 0; while(i < t->len >> 2) { - rxbuf[i] = spi_xchg_single(base, txbuf[i]); + rxbuf[i] = imx->xchg_single(imx, txbuf[i]); i++; } } - mxc_spi_chipselect(spi, 0); + imx->chipselect(spi, 0); return 0; } +static struct spi_imx_devtype_data spi_imx_devtype_data[] = { +#ifdef CONFIG_DRIVER_SPI_IMX_0_0 + [SPI_IMX_VER_0_0] = { + .chipselect = cspi_0_0_chipselect, + .xchg_single = cspi_0_0_xchg_single, + .init = cspi_0_0_init, + }, +#endif +#ifdef CONFIG_DRIVER_SPI_IMX_2_3 + [SPI_IMX_VER_2_3] = { + .chipselect = cspi_2_3_chipselect, + .xchg_single = cspi_2_3_xchg_single, + .init = cspi_2_3_init, + }, +#endif +}; + static int imx_spi_probe(struct device_d *dev) { struct spi_master *master; struct imx_spi *imx; struct spi_imx_master *pdata = dev->platform_data; + enum imx_spi_devtype version; imx = xzalloc(sizeof(*imx)); @@ -171,15 +369,22 @@ static int imx_spi_probe(struct device_d *dev) master->setup = imx_spi_setup; master->transfer = imx_spi_transfer; master->num_chipselect = pdata->num_chipselect; - imx->chipselect = pdata->chipselect; - - writel(MXC_CSPICTRL_ENABLE | MXC_CSPICTRL_MASTER, - dev->map_base + MXC_CSPICTRL); - writel(MXC_CSPIPERIOD_32KHZ, - dev->map_base + MXC_CSPIPERIOD); - while (readl(dev->map_base + MXC_CSPIINT) & MXC_CSPISTAT_RR) - readl(dev->map_base + MXC_CSPIRXDATA); - writel(0, dev->map_base + MXC_CSPIINT); + imx->cs_array = pdata->chipselect; + +#ifdef CONFIG_DRIVER_SPI_IMX_0_0 + if (cpu_is_mx27()) + version = SPI_IMX_VER_0_0; +#endif +#ifdef CONFIG_DRIVER_SPI_IMX_2_3 + if (cpu_is_mx51()) + version = SPI_IMX_VER_2_3; +#endif + imx->chipselect = spi_imx_devtype_data[version].chipselect; + imx->xchg_single = spi_imx_devtype_data[version].xchg_single; + imx->init = spi_imx_devtype_data[version].init; + imx->regs = (void __iomem *)dev->map_base; + + imx->init(imx); spi_register_master(master); diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 0c30c52fc9..05f1628fab 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -11,7 +11,7 @@ /*-------------------------------------------------------------------------*/ -#include <i2c/twl4030.h> +#include <mfd/twl4030.h> #include <usb/twl4030.h> #include <mach/ehci.h> #include <common.h> diff --git a/drivers/usb/otg/twl4030.c b/drivers/usb/otg/twl4030.c index 72edf25843..40771699ea 100644 --- a/drivers/usb/otg/twl4030.c +++ b/drivers/usb/otg/twl4030.c @@ -37,7 +37,7 @@ * MA 02111-1307 USA */ -#include <i2c/twl4030.h> +#include <mfd/twl4030.h> #include <usb/twl4030.h> #include <clock.h> |