@@ -238,13 +238,13 @@
sdi@80126000 {
compatible = "arm,pl18x", "arm,primecell";
reg = <0x80126000 0x1000>;
- interrupts = <60>;
+ interrupts = <0 60 0x4>;
status = "disabled";
};
sdi@80118000 {
compatible = "arm,pl18x", "arm,primecell";
reg = <0x80118000 0x1000>;
- interrupts = <50>;
+ interrupts = <0 50 0x4>;
status = "disabled";
};
sdi@80005000 {
@@ -262,7 +262,7 @@
sdi@80114000 {
compatible = "arm,pl18x", "arm,primecell";
reg = <0x80114000 0x1000>;
- interrupts = <99>;
+ interrupts = <0 99 0x4>;
status = "disabled";
};
sdi@80008000 {
@@ -87,13 +87,37 @@
};
};
+ // External Micro SD slot
sdi@80126000 {
- status = "enabled";
- cd-gpios = <&gpio6 26>;
+ arm,primecell-periphid = <0x10480180>;
+ #gpio-cells = <1>;
+ gpio-en = <217>; // <&gpio6 25>;
+ gpio-vsel = <228>; // <&gpio7 4>;
+ cd-gpios = <218>; // <&gpio6 26>;
+ cd-invert;
+
+ ocr_mask = <0x00020000>;
+ clock_frequency = <50000000>;
+ rx_src_dev_type = <29>;
+ tx_dst_dev_type = <29>;
+ mmc_cap_4_bit_data;
+ mmc_cap_mmc_highspeed;
+
+ status = "okay";
};
+ // On-board eMMC
sdi@80114000 {
- status = "enabled";
+ arm,primecell-periphid = <0x10480180>;
+ ocr_mask = <0x00020000>;
+ clock_frequency = <50000000>;
+ mmc_cap_4_bit_data;
+ mmc_cap_8_bit_data;
+ mmc_cap_mmc_highspeed;
+ rx_src_dev_type = <42>;
+ tx_dst_dev_type = <42>;
+
+ status = "okay";
};
uart@80120000 {
@@ -750,6 +750,8 @@ struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("arm,pl011", 0x80121000, "uart1", &uart1_plat),
OF_DEV_AUXDATA("arm,pl011", 0x80007000, "uart2", &uart2_plat),
OF_DEV_AUXDATA("arm,pl022", 0x80002000, "ssp0", &ssp0_plat),
+ OF_DEV_AUXDATA("arm,pl18x", 0x80126000, "sdi0", NULL),
+ OF_DEV_AUXDATA("arm,pl18x", 0x80114000, "sdi4", NULL),
{},
};
@@ -789,7 +791,6 @@ static void __init u8500_init_machine(void)
platform_add_devices(snowball_platform_devs,
ARRAY_SIZE(snowball_platform_devs));
- snowball_sdi_init(parent);
} else if (of_machine_is_compatible("st-ericsson,hrefv60+")) {
/*
* The HREFv60 board removed a GPIO expander and routed
@@ -1,5 +1,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+
+#include <plat/ste_dma40.h>
+
+#include "mmci.h"
/* MMCIPOWER bits */
#define MCI_DATA2DIREN (1 << 2)
@@ -37,6 +43,167 @@ static struct variant_data variant_ux500v2 = {
.blksz_datactrl16 = true,
};
+struct mmci_ux500_platform_data {
+ struct mmci_platform_data pdata;
+ int gpio_en;
+ int gpio_vsel;
+};
+
+static u32 mmci_ux500_vdd_handler(struct device *dev, unsigned int vdd,
+ unsigned char power_mode)
+{
+ struct mmci_ux500_platform_data *pdata =
+ container_of(dev->platform_data, struct mmci_ux500_platform_data, pdata);
+
+ switch (power_mode) {
+ case MMC_POWER_UP:
+ case MMC_POWER_ON:
+ /*
+ * Level shifter voltage should depend on vdd to when deciding
+ * on either 1.8V or 2.9V. Once the decision has been made the
+ * level shifter must be disabled and re-enabled with a changed
+ * select signal in order to switch the voltage. Since there is
+ * no framework support yet for indicating 1.8V in vdd, use the
+ * default 2.9V.
+ */
+ if (pdata->gpio_vsel)
+ gpio_direction_output(pdata->gpio_vsel, 0);
+ if (pdata->gpio_en)
+ gpio_direction_output(pdata->gpio_en, 1);
+ break;
+ case MMC_POWER_OFF:
+ if (pdata->gpio_vsel)
+ gpio_direction_output(pdata->gpio_vsel, 0);
+ if (pdata->gpio_en)
+ gpio_direction_output(pdata->gpio_en, 0);
+ break;
+ }
+
+ return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN |
+ MCI_DATA2DIREN | MCI_DATA31DIREN;
+}
+
+static int __devinit mmci_ux500_probe(struct amba_device *dev,
+ const struct amba_id *id)
+{
+ struct mmci_ux500_platform_data *ux500_pdata;
+ struct mmci_platform_data *pdata = dev->dev.platform_data;
+ struct device_node *np = dev->dev.of_node;
+ struct stedma40_chan_cfg *dma_tx_param;
+ struct stedma40_chan_cfg *dma_rx_param;
+ int val, ret = -EINVAL;
+
+ /* Check if we have already been populated by platform code. */
+ if (pdata)
+ return mmci_probe(dev, id);
+
+#ifdef CONFIG_OF
+ if (!np) {
+ pr_warning("No platform data or Device Tree found\n");
+ return -EINVAL;
+ }
+
+ ux500_pdata = kzalloc(sizeof(struct mmci_ux500_platform_data), GFP_KERNEL);
+ if (!ux500_pdata)
+ return -ENOMEM;
+
+ dma_tx_param = kzalloc(sizeof(struct stedma40_chan_cfg), GFP_KERNEL);
+ if (!dma_tx_param) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ dma_rx_param = kzalloc(sizeof(struct stedma40_chan_cfg), GFP_KERNEL);
+ if (!dma_rx_param) {
+ ret = -ENOMEM;
+ goto out2;
+ }
+
+ /* ST-Ericsson/Micro specific DMA attributes. */
+ ux500_pdata->gpio_vsel = 0;
+ ux500_pdata->gpio_en = 0;
+
+ of_property_read_u32(np, "gpio-en", &ux500_pdata->gpio_en);
+ of_property_read_u32(np, "gpio-vsel", &ux500_pdata->gpio_vsel);
+
+ if (ux500_pdata->gpio_vsel && ux500_pdata->gpio_en) {
+ ret = gpio_request(ux500_pdata->gpio_en, "level shifter enable");
+ if (ret) {
+ pr_warning("GPIO request for level shifter enable failed.\n");
+ goto out3;
+ }
+
+ ret = gpio_request(ux500_pdata->gpio_vsel, "level shifter 1v8-3v select");
+ if (ret) {
+ pr_warning("GPIO request for level shifter select failed.\n");
+ goto out3;
+ }
+
+ /* Select the default 2.9V and enable level shifter */
+ gpio_direction_output(ux500_pdata->gpio_vsel, 0);
+ gpio_direction_output(ux500_pdata->gpio_en, 1);
+
+ ux500_pdata->pdata.vdd_handler = mmci_ux500_vdd_handler;
+ }
+
+ ux500_pdata->pdata.dma_filter = stedma40_filter;
+
+ /* Mode. */
+ dma_tx_param->mode = STEDMA40_MODE_LOGICAL;
+ dma_rx_param->mode = STEDMA40_MODE_LOGICAL;
+
+ /* Direction. */
+ dma_tx_param->dir = STEDMA40_MEM_TO_PERIPH;
+ dma_rx_param->dir = STEDMA40_PERIPH_TO_MEM;
+
+ /* Device type. */
+ dma_tx_param->src_dev_type = STEDMA40_DEV_DST_MEMORY;
+
+ if (!of_property_read_u32(np, "tx_dst_dev_type", &val))
+ dma_tx_param->dst_dev_type = val;
+
+ dma_rx_param->dst_dev_type = STEDMA40_DEV_DST_MEMORY;
+
+ if (!of_property_read_u32(np, "rx_src_dev_type", &val))
+ dma_rx_param->src_dev_type = val;
+
+ /* Data width. */
+ dma_tx_param->src_info.data_width = STEDMA40_WORD_WIDTH;
+ dma_tx_param->dst_info.data_width = STEDMA40_WORD_WIDTH;
+ dma_rx_param->src_info.data_width = STEDMA40_WORD_WIDTH;
+ dma_rx_param->dst_info.data_width = STEDMA40_WORD_WIDTH;
+
+ ux500_pdata->pdata.dma_tx_param = dma_tx_param;
+ ux500_pdata->pdata.dma_rx_param = dma_rx_param;
+
+ dev->dev.platform_data = &ux500_pdata->pdata;
+
+ return mmci_probe(dev, id);
+
+out3:
+ kfree(dma_rx_param);
+out2:
+ kfree(dma_tx_param);
+out1:
+ kfree(ux500_pdata);
+#endif /* CONFIG_OF */
+
+ return ret;
+}
+
+static int __devexit mmci_ux500_remove(struct amba_device *dev)
+{
+ struct mmci_ux500_platform_data *pdata =
+ container_of(dev->dev.platform_data, struct mmci_ux500_platform_data, pdata);
+
+ kfree(pdata->pdata.dma_tx_param);
+ kfree(pdata->pdata.dma_tx_param);
+
+ mmci_remove(dev);
+
+ return 0;
+}
+
static struct amba_id mmci_ux500_ids[] = {
/* ST Micro variants */
{
@@ -68,8 +235,8 @@ static struct amba_driver mmci_ux500_driver = {
.drv = {
.name = DRIVER_NAME,
},
- .probe = mmci_probe,
- .remove = __devexit_p(mmci_remove),
+ .probe = mmci_ux500_probe,
+ .remove = __devexit_p(mmci_ux500_remove),
.suspend = mmci_suspend,
.resume = mmci_resume,
.id_table = mmci_ux500_ids,
Provide a means to collect attributes specific to ST-Ericsson's ux500 variant series. This patch registers itself as the AMBA driver to be called during the probe process. Once all attributes and ux500 specifics are are collected the normal mmci core probe is called. Signed-off-by: Lee Jones <lee.jones@linaro.org> --- arch/arm/boot/dts/db8500.dtsi | 6 +- arch/arm/boot/dts/snowball.dts | 30 ++++++- arch/arm/mach-ux500/board-mop500.c | 3 +- drivers/mmc/host/mmci-ux500.c | 171 +++++++++++++++++++++++++++++++++++- 4 files changed, 201 insertions(+), 9 deletions(-)