|
@@ -1272,10 +1272,14 @@ static struct clk atmel_mci0_pclk = {
|
|
|
struct platform_device *__init
|
|
|
at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
|
|
|
{
|
|
|
- struct mci_platform_data _data;
|
|
|
struct platform_device *pdev;
|
|
|
+ struct dw_dma_slave *dws;
|
|
|
|
|
|
- if (id != 0)
|
|
|
+ if (id != 0 || !data)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ /* Must have at least one usable slot */
|
|
|
+ if (!data->slot[0].bus_width && !data->slot[1].bus_width)
|
|
|
return NULL;
|
|
|
|
|
|
pdev = platform_device_alloc("atmel_mci", id);
|
|
@@ -1286,28 +1290,76 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
|
|
|
ARRAY_SIZE(atmel_mci0_resource)))
|
|
|
goto fail;
|
|
|
|
|
|
- if (!data) {
|
|
|
- data = &_data;
|
|
|
- memset(data, -1, sizeof(struct mci_platform_data));
|
|
|
- data->detect_pin = GPIO_PIN_NONE;
|
|
|
- data->wp_pin = GPIO_PIN_NONE;
|
|
|
- }
|
|
|
+ if (data->dma_slave)
|
|
|
+ dws = kmemdup(to_dw_dma_slave(data->dma_slave),
|
|
|
+ sizeof(struct dw_dma_slave), GFP_KERNEL);
|
|
|
+ else
|
|
|
+ dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL);
|
|
|
+
|
|
|
+ dws->slave.dev = &pdev->dev;
|
|
|
+ dws->slave.dma_dev = &dw_dmac0_device.dev;
|
|
|
+ dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT;
|
|
|
+ dws->cfg_hi = (DWC_CFGH_SRC_PER(0)
|
|
|
+ | DWC_CFGH_DST_PER(1));
|
|
|
+ dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL
|
|
|
+ | DWC_CFGL_HS_SRC_POL);
|
|
|
+
|
|
|
+ data->dma_slave = &dws->slave;
|
|
|
|
|
|
if (platform_device_add_data(pdev, data,
|
|
|
sizeof(struct mci_platform_data)))
|
|
|
goto fail;
|
|
|
|
|
|
- select_peripheral(PA(10), PERIPH_A, 0); /* CLK */
|
|
|
- select_peripheral(PA(11), PERIPH_A, 0); /* CMD */
|
|
|
- select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
|
|
|
- select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
|
|
|
- select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
|
|
|
- select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
|
|
|
+ /* CLK line is common to both slots */
|
|
|
+ select_peripheral(PA(10), PERIPH_A, 0);
|
|
|
|
|
|
- if (gpio_is_valid(data->detect_pin))
|
|
|
- at32_select_gpio(data->detect_pin, 0);
|
|
|
- if (gpio_is_valid(data->wp_pin))
|
|
|
- at32_select_gpio(data->wp_pin, 0);
|
|
|
+ switch (data->slot[0].bus_width) {
|
|
|
+ case 4:
|
|
|
+ select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
|
|
|
+ select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
|
|
|
+ select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
|
|
|
+ /* fall through */
|
|
|
+ case 1:
|
|
|
+ select_peripheral(PA(11), PERIPH_A, 0); /* CMD */
|
|
|
+ select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
|
|
|
+
|
|
|
+ if (gpio_is_valid(data->slot[0].detect_pin))
|
|
|
+ at32_select_gpio(data->slot[0].detect_pin, 0);
|
|
|
+ if (gpio_is_valid(data->slot[0].wp_pin))
|
|
|
+ at32_select_gpio(data->slot[0].wp_pin, 0);
|
|
|
+ break;
|
|
|
+ case 0:
|
|
|
+ /* Slot is unused */
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (data->slot[1].bus_width) {
|
|
|
+ case 4:
|
|
|
+ select_peripheral(PB(8), PERIPH_B, 0); /* DATA1 */
|
|
|
+ select_peripheral(PB(9), PERIPH_B, 0); /* DATA2 */
|
|
|
+ select_peripheral(PB(10), PERIPH_B, 0); /* DATA3 */
|
|
|
+ /* fall through */
|
|
|
+ case 1:
|
|
|
+ select_peripheral(PB(6), PERIPH_B, 0); /* CMD */
|
|
|
+ select_peripheral(PB(7), PERIPH_B, 0); /* DATA0 */
|
|
|
+
|
|
|
+ if (gpio_is_valid(data->slot[1].detect_pin))
|
|
|
+ at32_select_gpio(data->slot[1].detect_pin, 0);
|
|
|
+ if (gpio_is_valid(data->slot[1].wp_pin))
|
|
|
+ at32_select_gpio(data->slot[1].wp_pin, 0);
|
|
|
+ break;
|
|
|
+ case 0:
|
|
|
+ /* Slot is unused */
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ if (!data->slot[0].bus_width)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ data->slot[1].bus_width = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
atmel_mci0_pclk.dev = &pdev->dev;
|
|
|
|