From patchwork Tue Jun 9 11:53:52 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cyrille Pitchen X-Patchwork-Id: 6571861 Return-Path: X-Original-To: patchwork-linux-spi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 54FF49F399 for ; Tue, 9 Jun 2015 11:56:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6D64D204DF for ; Tue, 9 Jun 2015 11:56:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5D29A204AB for ; Tue, 9 Jun 2015 11:56:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933288AbbFILyH (ORCPT ); Tue, 9 Jun 2015 07:54:07 -0400 Received: from eusmtp01.atmel.com ([212.144.249.243]:18090 "EHLO eusmtp01.atmel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932813AbbFILyD (ORCPT ); Tue, 9 Jun 2015 07:54:03 -0400 Received: from tenerife.corp.atmel.com (10.161.101.13) by eusmtp01.atmel.com (10.161.101.31) with Microsoft SMTP Server id 14.3.235.1; Tue, 9 Jun 2015 13:53:58 +0200 From: Cyrille Pitchen To: , , CC: , , , , , , , , Cyrille Pitchen Subject: [PATCH v3 1/3] spi: atmel: add support for the internal chip-select of the spi controller Date: Tue, 9 Jun 2015 13:53:52 +0200 Message-ID: X-Mailer: git-send-email 1.8.2.2 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_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 patch relies on the CSAAT (Chip Select Active After Transfer) feature introduced by the version 2 of the spi controller. This new mode allows to use properly the internal chip-select output pin of the spi controller instead of using external gpios. Consequently, the "cs-gpios" device-tree property becomes optional. When the new CSAAT bit is set into the Chip Select Register, the internal chip-select output pin remains asserted till both the following conditions become true: - the LASTXFER bit is set into the Control Register (or the Transmit Data Register) - the Transmit Data Register and its shift register are empty. WARNING: if the LASTXFER bit is set into the Control Register then new data are written into the Transmit Data Register fast enough to keep its shifter not empty, the chip-select output pin remains asserted. Only when the shifter becomes empty, the chip-select output pin is unasserted. When the CSAAT bit is clear in the Chip Select Register, the LASTXFER bit is ignored in both the Control Register and the Transmit Data Register. The internal chip-select output pin remains active as long as the Transmit Data Register or its shift register are not empty. Signed-off-by: Cyrille Pitchen Acked-by: Nicolas Ferre --- drivers/spi/spi-atmel.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index a2f40b1..aa7d202 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -246,6 +246,7 @@ struct atmel_spi { bool use_dma; bool use_pdc; + bool use_cs_gpios; /* dmaengine data */ struct atmel_spi_dma dma; @@ -321,7 +322,8 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) } mr = spi_readl(as, MR); - gpio_set_value(asd->npcs_pin, active); + if (as->use_cs_gpios) + gpio_set_value(asd->npcs_pin, active); } else { u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; int i; @@ -337,7 +339,7 @@ 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) + if (as->use_cs_gpios && spi->chip_select != 0) gpio_set_value(asd->npcs_pin, active); spi_writel(as, MR, mr); } @@ -366,7 +368,9 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) asd->npcs_pin, active ? " (low)" : "", mr); - if (atmel_spi_is_v2(as) || spi->chip_select != 0) + if (!as->use_cs_gpios) + spi_writel(as, CR, SPI_BIT(LASTXFER)); + else if (atmel_spi_is_v2(as) || spi->chip_select != 0) gpio_set_value(asd->npcs_pin, !active); } @@ -996,6 +1000,8 @@ static int atmel_spi_setup(struct spi_device *spi) csr |= SPI_BIT(CPOL); if (!(spi->mode & SPI_CPHA)) csr |= SPI_BIT(NCPHA); + if (!as->use_cs_gpios) + csr |= SPI_BIT(CSAAT); /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs. * @@ -1009,7 +1015,9 @@ static int atmel_spi_setup(struct spi_device *spi) /* chipselect must have been muxed as GPIO (e.g. in board setup) */ npcs_pin = (unsigned long)spi->controller_data; - if (gpio_is_valid(spi->cs_gpio)) + if (!as->use_cs_gpios) + npcs_pin = spi->chip_select; + else if (gpio_is_valid(spi->cs_gpio)) npcs_pin = spi->cs_gpio; asd = spi->controller_state; @@ -1018,15 +1026,19 @@ static int atmel_spi_setup(struct spi_device *spi) if (!asd) return -ENOMEM; - ret = gpio_request(npcs_pin, dev_name(&spi->dev)); - if (ret) { - kfree(asd); - return ret; + if (as->use_cs_gpios) { + ret = gpio_request(npcs_pin, dev_name(&spi->dev)); + if (ret) { + kfree(asd); + return ret; + } + + gpio_direction_output(npcs_pin, + !(spi->mode & SPI_CS_HIGH)); } asd->npcs_pin = npcs_pin; spi->controller_state = asd; - gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH)); } asd->csr = csr; @@ -1338,6 +1350,13 @@ static int atmel_spi_probe(struct platform_device *pdev) atmel_get_caps(as); + as->use_cs_gpios = true; + if (atmel_spi_is_v2(as) && + !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) { + as->use_cs_gpios = false; + master->num_chipselect = 4; + } + as->use_dma = false; as->use_pdc = false; if (as->caps.has_dma_support) {