Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 977b06d0 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'spi/topic/pxa2xx', 'spi/topic/s3c64xx',...

Merge remote-tracking branches 'spi/topic/pxa2xx', 'spi/topic/s3c64xx', 'spi/topic/sh-msiof', 'spi/topic/sirf' and 'spi/topic/sun6i' into spi-next
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -36,7 +36,21 @@ Required properties:

Optional properties:
- clocks               : Must contain a reference to the functional clock.
- num-cs               : Total number of chip-selects (default is 1)
- num-cs               : Total number of chip selects (default is 1).
			 Up to 3 native chip selects are supported:
			   0: MSIOF_SYNC
			   1: MSIOF_SS1
			   2: MSIOF_SS2
			 Hardware limitations related to chip selects:
			   - Native chip selects are always deasserted in
			     between transfers that are part of the same
			     message.  Use cs-gpios to work around this.
			   - All slaves using native chip selects must use the
			     same spi-cs-high configuration.  Use cs-gpios to
			     work around this.
			   - When using GPIO chip selects, at least one native
			     chip select must be left unused, as it will be
			     driven anyway.
- dmas                 : Must contain a list of two references to DMA
			 specifiers, one for transmission, and one for
			 reception.
+2 −2
Original line number Diff line number Diff line
@@ -1237,7 +1237,7 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
	 * different chip_info, release previously requested GPIO
	 */
	if (chip->gpiod_cs) {
		gpio_free(desc_to_gpio(chip->gpiod_cs));
		gpiod_put(chip->gpiod_cs);
		chip->gpiod_cs = NULL;
	}

@@ -1417,7 +1417,7 @@ static void cleanup(struct spi_device *spi)

	if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods &&
	    chip->gpiod_cs)
		gpio_free(desc_to_gpio(chip->gpiod_cs));
		gpiod_put(chip->gpiod_cs);

	kfree(chip);
}
+4 −14
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 Samsung Electronics Ltd.
 *	Jaswinder Singh <jassi.brar@samsung.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright (c) 2009 Samsung Electronics Co., Ltd.
//      Jaswinder Singh <jassi.brar@samsung.com>

#include <linux/init.h>
#include <linux/module.h>
+94 −22
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -55,9 +56,14 @@ struct sh_msiof_spi_priv {
	void *rx_dma_page;
	dma_addr_t tx_dma_addr;
	dma_addr_t rx_dma_addr;
	unsigned short unused_ss;
	bool native_cs_inited;
	bool native_cs_high;
	bool slave_aborted;
};

#define MAX_SS	3	/* Maximum number of native chip selects */

#define TMDR1	0x00	/* Transmit Mode Register 1 */
#define TMDR2	0x04	/* Transmit Mode Register 2 */
#define TMDR3	0x08	/* Transmit Mode Register 3 */
@@ -91,6 +97,8 @@ struct sh_msiof_spi_priv {
#define MDR1_XXSTP	 0x00000001 /* Transmission/Reception Stop on FIFO */
/* TMDR1 */
#define TMDR1_PCON	 0x40000000 /* Transfer Signal Connection */
#define TMDR1_SYNCCH_MASK 0xc000000 /* Synchronization Signal Channel Select */
#define TMDR1_SYNCCH_SHIFT	 26 /* 0=MSIOF_SYNC, 1=MSIOF_SS1, 2=MSIOF_SS2 */

/* TMDR2 and RMDR2 */
#define MDR2_BITLEN1(i)	(((i) - 1) << 24) /* Data Size (8-32 bits) */
@@ -324,7 +332,7 @@ static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p)
	return val;
}

static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, u32 ss,
				      u32 cpol, u32 cpha,
				      u32 tx_hi_z, u32 lsb_first, u32 cs_high)
{
@@ -342,10 +350,13 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
	tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
	tmp |= lsb_first << MDR1_BITLSB_SHIFT;
	tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
	if (spi_controller_is_slave(p->master))
	if (spi_controller_is_slave(p->master)) {
		sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON);
	else
		sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
	} else {
		sh_msiof_write(p, TMDR1,
			       tmp | MDR1_TRMD | TMDR1_PCON |
			       (ss < MAX_SS ? ss : 0) << TMDR1_SYNCCH_SHIFT);
	}
	if (p->master->flags & SPI_MASTER_MUST_TX) {
		/* These bits are reserved if RX needs TX */
		tmp &= ~0x0000ffff;
@@ -528,8 +539,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
{
	struct device_node	*np = spi->master->dev.of_node;
	struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);

	pm_runtime_get_sync(&p->pdev->dev);
	u32 clr, set, tmp;

	if (!np) {
		/*
@@ -539,19 +549,31 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
		spi->cs_gpio = (uintptr_t)spi->controller_data;
	}

	/* Configure pins before deasserting CS */
	sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
				  !!(spi->mode & SPI_CPHA),
				  !!(spi->mode & SPI_3WIRE),
				  !!(spi->mode & SPI_LSB_FIRST),
				  !!(spi->mode & SPI_CS_HIGH));
	if (gpio_is_valid(spi->cs_gpio)) {
		gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
		return 0;
	}

	if (spi->cs_gpio >= 0)
		gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
	if (spi_controller_is_slave(p->master))
		return 0;

	if (p->native_cs_inited &&
	    (p->native_cs_high == !!(spi->mode & SPI_CS_HIGH)))
		return 0;

	/* Configure native chip select mode/polarity early */
	clr = MDR1_SYNCMD_MASK;
	set = MDR1_TRMD | TMDR1_PCON | MDR1_SYNCMD_SPI;
	if (spi->mode & SPI_CS_HIGH)
		clr |= BIT(MDR1_SYNCAC_SHIFT);
	else
		set |= BIT(MDR1_SYNCAC_SHIFT);
	pm_runtime_get_sync(&p->pdev->dev);
	tmp = sh_msiof_read(p, TMDR1) & ~clr;
	sh_msiof_write(p, TMDR1, tmp | set);
	pm_runtime_put(&p->pdev->dev);

	p->native_cs_high = spi->mode & SPI_CS_HIGH;
	p->native_cs_inited = true;
	return 0;
}

@@ -560,13 +582,20 @@ static int sh_msiof_prepare_message(struct spi_master *master,
{
	struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
	const struct spi_device *spi = msg->spi;
	u32 ss, cs_high;

	/* Configure pins before asserting CS */
	sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
	if (gpio_is_valid(spi->cs_gpio)) {
		ss = p->unused_ss;
		cs_high = p->native_cs_high;
	} else {
		ss = spi->chip_select;
		cs_high = !!(spi->mode & SPI_CS_HIGH);
	}
	sh_msiof_spi_set_pin_regs(p, ss, !!(spi->mode & SPI_CPOL),
				  !!(spi->mode & SPI_CPHA),
				  !!(spi->mode & SPI_3WIRE),
				  !!(spi->mode & SPI_LSB_FIRST),
				  !!(spi->mode & SPI_CS_HIGH));
				  !!(spi->mode & SPI_LSB_FIRST), cs_high);
	return 0;
}

@@ -922,9 +951,8 @@ static int sh_msiof_transfer_one(struct spi_master *master,

		ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l);
		if (ret == -EAGAIN) {
			pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
				     dev_driver_string(&p->pdev->dev),
				     dev_name(&p->pdev->dev));
			dev_warn_once(&p->pdev->dev,
				"DMA not available, falling back to PIO\n");
			break;
		}
		if (ret)
@@ -1081,6 +1109,45 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
}
#endif

static int sh_msiof_get_cs_gpios(struct sh_msiof_spi_priv *p)
{
	struct device *dev = &p->pdev->dev;
	unsigned int used_ss_mask = 0;
	unsigned int cs_gpios = 0;
	unsigned int num_cs, i;
	int ret;

	ret = gpiod_count(dev, "cs");
	if (ret <= 0)
		return 0;

	num_cs = max_t(unsigned int, ret, p->master->num_chipselect);
	for (i = 0; i < num_cs; i++) {
		struct gpio_desc *gpiod;

		gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS);
		if (!IS_ERR(gpiod)) {
			cs_gpios++;
			continue;
		}

		if (PTR_ERR(gpiod) != -ENOENT)
			return PTR_ERR(gpiod);

		if (i >= MAX_SS) {
			dev_err(dev, "Invalid native chip select %d\n", i);
			return -EINVAL;
		}
		used_ss_mask |= BIT(i);
	}
	p->unused_ss = ffz(used_ss_mask);
	if (cs_gpios && p->unused_ss >= MAX_SS) {
		dev_err(dev, "No unused native chip select available\n");
		return -EINVAL;
	}
	return 0;
}

static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev,
	enum dma_transfer_direction dir, unsigned int id, dma_addr_t port_addr)
{
@@ -1294,13 +1361,18 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
	if (p->info->rx_fifo_override)
		p->rx_fifo_size = p->info->rx_fifo_override;

	/* Setup GPIO chip selects */
	master->num_chipselect = p->info->num_chipselect;
	ret = sh_msiof_get_cs_gpios(p);
	if (ret)
		goto err1;

	/* init master code */
	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
	master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
	master->flags = chipdata->master_flags;
	master->bus_num = pdev->id;
	master->dev.of_node = pdev->dev.of_node;
	master->num_chipselect = p->info->num_chipselect;
	master->setup = sh_msiof_spi_setup;
	master->prepare_message = sh_msiof_prepare_message;
	master->slave_abort = sh_msiof_slave_abort;
+2 −2
Original line number Diff line number Diff line
@@ -1072,7 +1072,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
	struct sirfsoc_spi *sspi;
	struct spi_master *master;
	struct resource *mem_res;
	struct sirf_spi_comp_data *spi_comp_data;
	const struct sirf_spi_comp_data *spi_comp_data;
	int irq;
	int ret;
	const struct of_device_id *match;
@@ -1092,7 +1092,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
	platform_set_drvdata(pdev, master);
	sspi = spi_master_get_devdata(master);
	sspi->fifo_full_offset = ilog2(sspi->fifo_size);
	spi_comp_data = (struct sirf_spi_comp_data *)match->data;
	spi_comp_data = match->data;
	sspi->regs = spi_comp_data->regs;
	sspi->type = spi_comp_data->type;
	sspi->fifo_level_chk_mask = (sspi->fifo_size / 4) - 1;
Loading