From patchwork Mon Jul 28 11:43:40 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Prchal X-Patchwork-Id: 4633531 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id C1867C0338 for ; Mon, 28 Jul 2014 11:46:17 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C855420179 for ; Mon, 28 Jul 2014 11:46:16 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D3E322017D for ; Mon, 28 Jul 2014 11:46:15 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XBjM0-0005wB-FS; Mon, 28 Jul 2014 11:44:32 +0000 Received: from router.aksignal.cz ([188.175.113.102]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XBjLw-0005gS-E9 for linux-arm-kernel@lists.infradead.org; Mon, 28 Jul 2014 11:44:29 +0000 Received: from localhost (localhost [127.0.0.1]) by router.aksignal.cz (Postfix) with ESMTP id CD74854C001; Mon, 28 Jul 2014 13:43:56 +0200 (CEST) X-Virus-Scanned: by amavisd-new at aksignal.cz Received: from router.aksignal.cz ([127.0.0.1]) by localhost (router.aksignal.cz [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ozO69huxlip5; Mon, 28 Jul 2014 13:43:54 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by router.aksignal.cz (Postfix) with ESMTP id DCE4654C002; Mon, 28 Jul 2014 13:43:53 +0200 (CEST) Received: from localhost.localdomain (unknown [10.0.1.101]) by router.aksignal.cz (Postfix) with ESMTP id AD73F54C001; Mon, 28 Jul 2014 13:43:53 +0200 (CEST) From: Jiri Prchal To: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, nicolas.ferre@atmel.com, voice.shen@atmel.com Subject: [PATCH] ARM: at91: spi: request all csgpio in spi probe Date: Mon, 28 Jul 2014 13:43:40 +0200 Message-Id: X-Mailer: git-send-email 1.9.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140728_044428_874241_CAC23DF4 X-CRM114-Status: GOOD ( 17.54 ) X-Spam-Score: -0.6 (/) Cc: Jiri Prchal X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This fix problem with PA14 set as periph A left from ROMBOOT and need it to be set to gpio before spi bus communicate with chip on CS0 on other gpio. As I reported a week ago. Request all csgpios in spi_probe since cs depends on each other and must be all of them in right state before any communication on bus. They are part of bus, like miso, mosi, clk, not part of chips, they are defined in parent spi node, not in child chip node. Csgpio moved to atmel_spi struct as part of master bus. Signed-off-by: Jiri Prchal --- drivers/spi/spi-atmel.c | 68 +++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 92a6f0d..1fb7bb9 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -22,11 +22,14 @@ #include #include #include +#include #include #include #include +#define DRIVER_NAME "atmel-spi" + /* SPI register offsets */ #define SPI_CR 0x0000 #define SPI_MR 0x0004 @@ -242,11 +245,13 @@ struct atmel_spi { bool keep_cs; bool cs_active; + + /* chip selects */ + unsigned int csgpio[]; }; /* Controller-specific per-slave state */ struct atmel_spi_device { - unsigned int npcs_pin; u32 csr; }; @@ -312,7 +317,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) } mr = spi_readl(as, MR); - gpio_set_value(asd->npcs_pin, active); + gpio_set_value(as->csgpio[spi->chip_select], active); } else { u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; int i; @@ -329,18 +334,16 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); if (spi->chip_select != 0) - gpio_set_value(asd->npcs_pin, active); + gpio_set_value(as->csgpio[spi->chip_select], active); spi_writel(as, MR, mr); } dev_dbg(&spi->dev, "activate %u%s, mr %08x\n", - asd->npcs_pin, active ? " (high)" : "", - mr); + as->csgpio[spi->chip_select], active ? " (high)" : "", mr); } static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) { - struct atmel_spi_device *asd = spi->controller_state; unsigned active = spi->mode & SPI_CS_HIGH; u32 mr; @@ -354,11 +357,10 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) } dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x\n", - asd->npcs_pin, active ? " (low)" : "", - mr); + as->csgpio[spi->chip_select], active ? " (low)" : "", mr); if (atmel_spi_is_v2(as) || spi->chip_select != 0) - gpio_set_value(asd->npcs_pin, !active); + gpio_set_value(as->csgpio[spi->chip_select], !active); } static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock) @@ -989,8 +991,6 @@ static int atmel_spi_setup(struct spi_device *spi) struct atmel_spi_device *asd; u32 csr; unsigned int bits = spi->bits_per_word; - unsigned int npcs_pin; - int ret; as = spi_master_get_devdata(spi->master); @@ -1017,27 +1017,13 @@ static int atmel_spi_setup(struct spi_device *spi) csr |= SPI_BF(DLYBS, 0); csr |= SPI_BF(DLYBCT, 0); - /* chipselect must have been muxed as GPIO (e.g. in board setup) */ - npcs_pin = (unsigned int)spi->controller_data; - - if (gpio_is_valid(spi->cs_gpio)) - npcs_pin = spi->cs_gpio; - asd = spi->controller_state; if (!asd) { asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL); if (!asd) return -ENOMEM; - ret = gpio_request(npcs_pin, dev_name(&spi->dev)); - if (ret) { - kfree(asd); - return ret; - } - - asd->npcs_pin = npcs_pin; spi->controller_state = asd; - gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH)); } asd->csr = csr; @@ -1290,6 +1276,15 @@ static int atmel_spi_probe(struct platform_device *pdev) int ret; struct spi_master *master; struct atmel_spi *as; + struct device_node *np = pdev->dev.of_node; + int num_cs, i; + + if (!np) + return -EINVAL; + + num_cs = of_gpio_named_count(np, "cs-gpios"); + if (num_cs < 0) + return num_cs; /* Select default pin state */ pinctrl_pm_select_default_state(&pdev->dev); @@ -1308,7 +1303,7 @@ static int atmel_spi_probe(struct platform_device *pdev) /* setup spi core then atmel-specific driver state */ ret = -ENOMEM; - master = spi_alloc_master(&pdev->dev, sizeof(*as)); + master = spi_alloc_master(&pdev->dev, sizeof(*as) + num_cs * sizeof(unsigned)); if (!master) goto out_free; @@ -1317,7 +1312,7 @@ static int atmel_spi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); master->dev.of_node = pdev->dev.of_node; master->bus_num = pdev->id; - master->num_chipselect = master->dev.of_node ? 0 : 4; + master->num_chipselect = num_cs; master->setup = atmel_spi_setup; master->transfer_one_message = atmel_spi_transfer_one_message; master->cleanup = atmel_spi_cleanup; @@ -1325,6 +1320,25 @@ static int atmel_spi_probe(struct platform_device *pdev) as = spi_master_get_devdata(master); + for (i = 0; i < master->num_chipselect; ++i) { + ret = of_get_named_gpio(np, "cs-gpios", i); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get csgpio#%u (%d)\n", + i, ret); + goto out_free; + } + as->csgpio[i] = ret; + dev_dbg(&pdev->dev, "csgpio#%u = %u\n", i, as->csgpio[i]); + ret = devm_gpio_request_one(&pdev->dev, as->csgpio[i], + GPIOF_OUT_INIT_HIGH, DRIVER_NAME); + if (ret < 0) { + dev_err(&pdev->dev, + "failed to configure csgpio#%u (%d)\n", + i, ret); + goto out_free; + } + } + /* * Scratch buffer is used for throwaway rx and tx data. * It's coherent to minimize dcache pollution.