From patchwork Mon Jan 14 20:27:01 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anatolij Gustschin X-Patchwork-Id: 1973511 Return-Path: X-Original-To: patchwork-spi-devel-general@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by patchwork1.kernel.org (Postfix) with ESMTP id 88D4E3FE33 for ; Mon, 14 Jan 2013 20:27:21 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=sfs-ml-2.v29.ch3.sourceforge.com) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1Tuqcq-0005by-Vr; Mon, 14 Jan 2013 20:27:21 +0000 Received: from sog-mx-2.v43.ch3.sourceforge.com ([172.29.43.192] helo=mx.sourceforge.net) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1Tuqcp-0005bl-E7 for spi-devel-general@lists.sourceforge.net; Mon, 14 Jan 2013 20:27:19 +0000 X-ACL-Warn: Received: from mail-out.m-online.net ([212.18.0.9]) by sog-mx-2.v43.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.76) id 1Tuqco-0005bC-AD for spi-devel-general@lists.sourceforge.net; Mon, 14 Jan 2013 20:27:19 +0000 Received: from frontend1.mail.m-online.net (unknown [192.168.8.180]) by mail-out.m-online.net (Postfix) with ESMTP id 3YlR6t5kcFz4KK6p; Mon, 14 Jan 2013 21:27:02 +0100 (CET) X-Auth-Info: QNB6OL4+iyR+Ho6Puh+tfJmvN9T2CFLXGniSoxgBCqI= Received: from localhost (p4FDE760D.dip.t-dialin.net [79.222.118.13]) (using TLSv1 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA id 3YlR6t2QJ2zbbfN; Mon, 14 Jan 2013 21:27:02 +0100 (CET) From: Anatolij Gustschin To: spi-devel-general@lists.sourceforge.net Subject: [PATCH 2/2] spi: spi-mpc512x-psc: add support for gpio chip selects Date: Mon, 14 Jan 2013 21:27:01 +0100 Message-Id: <1358195221-18488-2-git-send-email-agust@denx.de> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1358195221-18488-1-git-send-email-agust@denx.de> References: <1358195221-18488-1-git-send-email-agust@denx.de> X-Spam-Score: 0.0 (/) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [212.18.0.9 listed in list.dnswl.org] X-Headers-End: 1Tuqco-0005bC-AD X-BeenThere: spi-devel-general@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux SPI core/device drivers discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: spi-devel-general-bounces@lists.sourceforge.net Currently the driver only uses one internal chip select. Add support for gpio chip selects configured by gpio specifiers in the device tree. Signed-off-by: Anatolij Gustschin --- drivers/spi/spi-mpc512x-psc.c | 80 ++++++++++++++++++++++++++++++++++++++--- 1 files changed, 75 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 89480b2..4b2f391 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,8 @@ struct mpc512x_psc_spi { spinlock_t lock; /* Message queue lock */ struct completion done; + int num_cs; + int chipselects[0]; }; /* controller state */ @@ -277,6 +280,7 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi) { struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); struct mpc512x_psc_spi_cs *cs = spi->controller_state; + int gpio = mps->chipselects[spi->chip_select]; unsigned long flags; if (spi->bits_per_word % 8) @@ -292,6 +296,9 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi) cs->bits_per_word = spi->bits_per_word; cs->speed_hz = spi->max_speed_hz; + if (gpio_is_valid(gpio)) + gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); + spin_lock_irqsave(&mps->lock, flags); if (!mps->busy) mpc512x_psc_spi_deactivate_cs(spi); @@ -405,6 +412,27 @@ static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id) return IRQ_NONE; } +static void mpc512x_spi_cs_control(struct spi_device *spi, bool on) +{ + struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); + int gpio = mps->chipselects[spi->chip_select]; + + gpio_set_value(gpio, on); +} + +static int mpc512x_spi_cs_num(struct device *dev) +{ + int num_cs, ret; + + ret = of_property_read_u32(dev->of_node, "num-cs", &num_cs); + if (ret < 0) { + dev_warn(dev, "no num-cs property\n"); + return of_gpio_named_count(dev->of_node, "cs-gpios"); + } + + return num_cs; +} + /* bus_num is used only for the case dev->platform_data == NULL */ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, u32 size, unsigned int irq, @@ -415,8 +443,17 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, struct spi_master *master; int ret; void *tempp; + int i = 0, max_cs_num = 0; + int use_internal_cs = 0; + int num_cs; + + num_cs = mpc512x_spi_cs_num(dev); + if (!num_cs) + use_internal_cs = 1; - master = spi_alloc_master(dev, sizeof *mps); + dev_dbg(dev, "using %d gpio chipselects\n", num_cs); + + master = spi_alloc_master(dev, sizeof(*mps) + sizeof(int) * num_cs); if (master == NULL) return -ENOMEM; @@ -425,12 +462,14 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, mps->irq = irq; if (pdata == NULL) { - dev_err(dev, "probe called without platform data, no " - "cs_control function will be called\n"); - mps->cs_control = NULL; mps->sysclk = 0; master->bus_num = bus_num; - master->num_chipselect = 255; + if (use_internal_cs) { + mps->cs_control = NULL; + master->num_chipselect = 1; + } else { + mps->cs_control = mpc512x_spi_cs_control; + } } else { mps->cs_control = pdata->cs_control; mps->sysclk = pdata->sysclk; @@ -438,6 +477,28 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, master->num_chipselect = pdata->max_chipselect; } + if (!pdata && !use_internal_cs) { + for (i = 0; i < num_cs; i++) { + int cs_gpio = of_get_named_gpio(dev->of_node, + "cs-gpios", i); + + dev_dbg(dev, "cs %d: gpio %d\n", i, cs_gpio); + mps->chipselects[i] = cs_gpio; + if (!gpio_is_valid(cs_gpio)) + continue; + + max_cs_num = max(max_cs_num, cs_gpio); + ret = gpio_request(mps->chipselects[i], + "psc-spi cs"); + if (ret) { + dev_err(dev, "can't get CS gpio: %d\n", ret); + goto free_cs_gpios; + } + } + master->num_chipselect = max_cs_num; + mps->num_cs = num_cs; + } + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; master->setup = mpc512x_psc_spi_setup; master->transfer = mpc512x_psc_spi_transfer; @@ -485,6 +546,11 @@ unreg_master: destroy_workqueue(mps->workqueue); free_irq: free_irq(mps->irq, mps); +free_cs_gpios: + while (--i >= 0) { + if (gpio_is_valid(mps->chipselects[i])) + gpio_free(mps->chipselects[i]); + } free_master: if (mps->psc) iounmap(mps->psc); @@ -497,6 +563,7 @@ static int mpc512x_psc_spi_do_remove(struct device *dev) { struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); + int i; flush_workqueue(mps->workqueue); destroy_workqueue(mps->workqueue); @@ -504,6 +571,9 @@ static int mpc512x_psc_spi_do_remove(struct device *dev) free_irq(mps->irq, mps); if (mps->psc) iounmap(mps->psc); + for (i = 0; i < mps->num_cs; i++) + if (gpio_is_valid(mps->chipselects[i])) + gpio_free(mps->chipselects[i]); spi_master_put(master); return 0;