From patchwork Mon Jan 14 07:34:30 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wenyou Yang X-Patchwork-Id: 1971481 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 6BBE0DF23A for ; Mon, 14 Jan 2013 07:45:34 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TuegK-0007ly-Io; Mon, 14 Jan 2013 07:42:09 +0000 Received: from newsmtp5.atmel.com ([204.2.163.5] helo=sjogate2.atmel.com) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TuefL-0007a3-7p for linux-arm-kernel@lists.infradead.org; Mon, 14 Jan 2013 07:41:09 +0000 Received: from penbh01.corp.atmel.com ([10.168.5.31]) by sjogate2.atmel.com (8.13.6/8.13.6) with ESMTP id r0E7ZgQA026957; Sun, 13 Jan 2013 23:35:43 -0800 (PST) Received: from penmb01.corp.atmel.com ([10.168.5.33]) by penbh01.corp.atmel.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 14 Jan 2013 15:41:01 +0800 Received: from shaarm01.corp.atmel.com ([10.217.6.34]) by penmb01.corp.atmel.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 14 Jan 2013 15:41:00 +0800 From: Wenyou Yang To: linux-arm-kernel@lists.infradead.org Subject: [v4 PATCH 05/12] spi/atmel_spi: update the dt support Date: Mon, 14 Jan 2013 15:34:30 +0800 Message-Id: <1358148877-18679-6-git-send-email-wenyou.yang@atmel.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1358148877-18679-1-git-send-email-wenyou.yang@atmel.com> References: <1358148877-18679-1-git-send-email-wenyou.yang@atmel.com> X-OriginalArrivalTime: 14 Jan 2013 07:41:00.0917 (UTC) FILETIME=[7FBBBA50:01CDF22A] X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130114_024107_594635_F6A03E35 X-CRM114-Status: GOOD ( 21.91 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: richard.genoud@gmail.com, JM.Lin@atmel.com, nicolas.ferre@atmel.com, linux-kernel@vger.kernel.org, wenyou.yang@atmel.com, plagnioj@jcrosoft.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org To meet the different spi IP version of atmel SoC, add the more compatible with different config and devtype. The "has_dma_support" is used to select the dma engine transfer mode. The "has_wdrbt" indicate if there is the "WDRBT" bit in the Mode Register, WDRBT (Wait Data Read Before Transfer),if WDRBT is set, a transfer can start only if the Receive Data Register is empty,i.e. does not contain any unread data, to prevent overrun error in reception Signed-off-by: Wenyou Yang --- drivers/spi/spi-atmel.c | 134 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 115 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 8f6f0a0..43c1f63 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -71,6 +71,8 @@ #define SPI_FDIV_SIZE 1 #define SPI_MODFDIS_OFFSET 4 #define SPI_MODFDIS_SIZE 1 +#define SPI_WDRBT_OFFSET 5 +#define SPI_WDRBT_SIZE 1 #define SPI_LLB_OFFSET 7 #define SPI_LLB_SIZE 1 #define SPI_PCS_OFFSET 16 @@ -186,6 +188,12 @@ * DMA transfers; transfer queue progress is driven by IRQs. The clock * framework provides the base clock, subdivided for each spi_device. */ +struct atmel_spi_pdata { + u8 version; + bool has_dma_support; + bool has_wdrbt; +}; + struct atmel_spi { spinlock_t lock; unsigned long flags; @@ -204,6 +212,7 @@ struct atmel_spi { struct spi_transfer *next_transfer; unsigned long next_remaining_bytes; int done_status; + struct atmel_spi_pdata *pdata; void *buffer; dma_addr_t buffer_dma; @@ -218,6 +227,69 @@ struct atmel_spi_device { #define BUFFER_SIZE PAGE_SIZE #define INVALID_DMA_ADDRESS 0xffffffff +static struct atmel_spi_pdata at91rm9200_config = { + .version = 1, + .has_dma_support = false, + .has_wdrbt = false, +}; + +static struct atmel_spi_pdata at91sam9260_config = { + .version = 2, + .has_dma_support = false, + .has_wdrbt = false, +}; + +static struct atmel_spi_pdata at91sam9g45_config = { + .version = 2, + .has_dma_support = false, + .has_wdrbt = true, +}; + +static struct atmel_spi_pdata at91sam9x5_config = { + .version = 2, + .has_dma_support = true, + .has_wdrbt = true, +}; + +static const struct platform_device_id atmel_spi_devtypes[] = { + { + .name = "spi-at91rm9200", + .driver_data = (unsigned long) &at91rm9200_config, + }, { + .name = "spi-at91sam9260", + .driver_data = (unsigned long) &at91sam9260_config, + }, { + .name = "spi-at91sam9g45", + .driver_data = (unsigned long) &at91sam9g45_config, + }, { + .name = "spi-at91sam9x5", + .driver_data = (unsigned long) &at91sam9x5_config, + }, { + /* sentinel */ + } +}; + +#if defined(CONFIG_OF) +static const struct of_device_id atmel_spi_dt_ids[] = { + { + .compatible = "atmel,at91rm9200-spi", + .data = &at91rm9200_config, + } , { + .compatible = "atmel,at91sam9260-spi", + .data = &at91sam9260_config, + } , { + .compatible = "atmel,at91sam9g45-spi", + .data = &at91sam9g45_config, + } , { + .compatible = "atmel,at91sam9x5-spi", + .data = &at91sam9x5_config, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids); +#endif + /* * Version 2 of the SPI controller has * - CR.LASTXFER @@ -230,11 +302,12 @@ struct atmel_spi_device { * register, but I haven't checked that it exists on all chips, and * this is cheaper anyway. */ -static bool atmel_spi_is_v2(void) +static bool atmel_spi_is_v2(struct atmel_spi *as) { - return !cpu_is_at91rm9200(); + return as->pdata->version == 2; } + /* * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby * they assume that spi slave device state will not change on deselect, so @@ -266,15 +339,21 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; - if (atmel_spi_is_v2()) { + if (atmel_spi_is_v2(as)) { /* * Always use CSR0. This ensures that the clock * switches to the correct idle polarity before we * toggle the CS. */ spi_writel(as, CSR0, asd->csr); - spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS) - | SPI_BIT(MSTR)); + + if (as->pdata->has_wdrbt) + spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MSTR) + | SPI_BIT(MODFDIS) | SPI_BIT(WDRBT)); + else + spi_writel(as, MR, SPI_BF(PCS, 0x0e) + | SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); + mr = spi_readl(as, MR); gpio_set_value(asd->npcs_pin, active); } else { @@ -321,7 +400,7 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) asd->npcs_pin, active ? " (low)" : "", mr); - if (atmel_spi_is_v2() || spi->chip_select != 0) + if (atmel_spi_is_v2(as) || spi->chip_select != 0) gpio_set_value(asd->npcs_pin, !active); } @@ -734,7 +813,7 @@ static int atmel_spi_setup(struct spi_device *spi) } /* see notes above re chipselect */ - if (!atmel_spi_is_v2() + if (!atmel_spi_is_v2(as) && spi->chip_select == 0 && (spi->mode & SPI_CS_HIGH)) { dev_dbg(&spi->dev, "setup: can't be active-high\n"); @@ -743,7 +822,7 @@ static int atmel_spi_setup(struct spi_device *spi) /* v1 chips start out at half the peripheral bus speed. */ bus_hz = clk_get_rate(as->clk); - if (!atmel_spi_is_v2()) + if (!atmel_spi_is_v2(as)) bus_hz /= 2; if (spi->max_speed_hz) { @@ -817,7 +896,7 @@ static int atmel_spi_setup(struct spi_device *spi) "setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n", bus_hz / scbr, bits, spi->mode, spi->chip_select, csr); - if (!atmel_spi_is_v2()) + if (!atmel_spi_is_v2(as)) spi_writel(as, CSR0 + 4 * spi->chip_select, csr); return 0; @@ -921,6 +1000,21 @@ static void atmel_spi_cleanup(struct spi_device *spi) kfree(asd); } +static struct atmel_spi_pdata * __devinit atmel_spi_get_driver_data( + struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(atmel_spi_dt_ids, pdev->dev.of_node); + if (!match) + return NULL; + return (struct atmel_spi_pdata *) match->data; + } + + return (struct atmel_spi_pdata *) + platform_get_device_id(pdev)->driver_data; +} + /*-------------------------------------------------------------------------*/ static int atmel_spi_probe(struct platform_device *pdev) @@ -987,11 +1081,21 @@ static int atmel_spi_probe(struct platform_device *pdev) if (ret) goto out_unmap_regs; + as->pdata = atmel_spi_get_driver_data(pdev); + if (!as->pdata) + goto out_unmap_regs; + /* Initialize the hardware */ clk_enable(clk); spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ - spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); + + if (as->pdata->has_wdrbt) + spi_writel(as, MR, + SPI_BIT(MSTR) | SPI_BIT(MODFDIS) | SPI_BIT(WDRBT)); + else + spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); + spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); spi_writel(as, CR, SPI_BIT(SPIEN)); @@ -1084,21 +1188,13 @@ static int atmel_spi_resume(struct platform_device *pdev) #define atmel_spi_resume NULL #endif -#if defined(CONFIG_OF) -static const struct of_device_id atmel_spi_dt_ids[] = { - { .compatible = "atmel,at91rm9200-spi" }, - { /* sentinel */ } -}; - -MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids); -#endif - static struct platform_driver atmel_spi_driver = { .driver = { .name = "atmel_spi", .owner = THIS_MODULE, .of_match_table = of_match_ptr(atmel_spi_dt_ids), }, + .id_table = atmel_spi_devtypes, .suspend = atmel_spi_suspend, .resume = atmel_spi_resume, .probe = atmel_spi_probe,