Commit b14a8a80 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'spi/fix/atmel', 'spi/fix/mvbeu' and 'spi/fix/spidev' into spi-linus

Loading
Loading
Loading
Loading
+44 −12
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>

@@ -295,6 +296,7 @@ struct atmel_spi {
	int			irq;
	struct clk		*clk;
	struct platform_device	*pdev;
	unsigned long		spi_clk;

	struct spi_transfer	*current_transfer;
	int			current_remaining_bytes;
@@ -864,7 +866,7 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
	unsigned long		bus_hz;

	/* v1 chips start out at half the peripheral bus speed. */
	bus_hz = clk_get_rate(as->clk);
	bus_hz = as->spi_clk;
	if (!atmel_spi_is_v2(as))
		bus_hz /= 2;

@@ -1204,7 +1206,6 @@ static int atmel_spi_setup(struct spi_device *spi)
	u32			csr;
	unsigned int		bits = spi->bits_per_word;
	unsigned int		npcs_pin;
	int			ret;

	as = spi_master_get_devdata(spi->master);

@@ -1247,16 +1248,9 @@ static int atmel_spi_setup(struct spi_device *spi)
		if (!asd)
			return -ENOMEM;

		if (as->use_cs_gpios) {
			ret = gpio_request(npcs_pin, dev_name(&spi->dev));
			if (ret) {
				kfree(asd);
				return ret;
			}

		if (as->use_cs_gpios)
			gpio_direction_output(npcs_pin,
					      !(spi->mode & SPI_CS_HIGH));
		}

		asd->npcs_pin = npcs_pin;
		spi->controller_state = asd;
@@ -1471,13 +1465,11 @@ msg_done:
static void atmel_spi_cleanup(struct spi_device *spi)
{
	struct atmel_spi_device	*asd = spi->controller_state;
	unsigned		gpio = (unsigned long) spi->controller_data;

	if (!asd)
		return;

	spi->controller_state = NULL;
	gpio_free(gpio);
	kfree(asd);
}

@@ -1499,6 +1491,39 @@ static void atmel_get_caps(struct atmel_spi *as)
}

/*-------------------------------------------------------------------------*/
static int atmel_spi_gpio_cs(struct platform_device *pdev)
{
	struct spi_master	*master = platform_get_drvdata(pdev);
	struct atmel_spi	*as = spi_master_get_devdata(master);
	struct device_node	*np = master->dev.of_node;
	int			i;
	int			ret = 0;
	int			nb = 0;

	if (!as->use_cs_gpios)
		return 0;

	if (!np)
		return 0;

	nb = of_gpio_named_count(np, "cs-gpios");
	for (i = 0; i < nb; i++) {
		int cs_gpio = of_get_named_gpio(pdev->dev.of_node,
						"cs-gpios", i);

			if (cs_gpio == -EPROBE_DEFER)
				return cs_gpio;

			if (gpio_is_valid(cs_gpio)) {
				ret = devm_gpio_request(&pdev->dev, cs_gpio,
							dev_name(&pdev->dev));
				if (ret)
					return ret;
			}
	}

	return 0;
}

static int atmel_spi_probe(struct platform_device *pdev)
{
@@ -1577,6 +1602,10 @@ static int atmel_spi_probe(struct platform_device *pdev)
		master->num_chipselect = 4;
	}

	ret = atmel_spi_gpio_cs(pdev);
	if (ret)
		goto out_unmap_regs;

	as->use_dma = false;
	as->use_pdc = false;
	if (as->caps.has_dma_support) {
@@ -1606,6 +1635,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
	ret = clk_prepare_enable(clk);
	if (ret)
		goto out_free_irq;

	as->spi_clk = clk_get_rate(clk);

	spi_writel(as, CR, SPI_BIT(SWRST));
	spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
	if (as->caps.has_wdrbt) {
+54 −29
Original line number Diff line number Diff line
@@ -138,37 +138,62 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
	tclk_hz = clk_get_rate(orion_spi->clk);

	if (devdata->typ == ARMADA_SPI) {
		unsigned int clk, spr, sppr, sppr2, err;
		unsigned int best_spr, best_sppr, best_err;
		/*
		 * Given the core_clk (tclk_hz) and the target rate (speed) we
		 * determine the best values for SPR (in [0 .. 15]) and SPPR (in
		 * [0..7]) such that
		 *
		 * 	core_clk / (SPR * 2 ** SPPR)
		 *
		 * is as big as possible but not bigger than speed.
		 */

		best_err = speed;
		best_spr = 0;
		best_sppr = 0;
		/* best integer divider: */
		unsigned divider = DIV_ROUND_UP(tclk_hz, speed);
		unsigned spr, sppr;

		/* Iterate over the valid range looking for best fit */
		for (sppr = 0; sppr < 8; sppr++) {
			sppr2 = 0x1 << sppr;
		if (divider < 16) {
			/* This is the easy case, divider is less than 16 */
			spr = divider;
			sppr = 0;

			spr = tclk_hz / sppr2;
			spr = DIV_ROUND_UP(spr, speed);
			if ((spr == 0) || (spr > 15))
				continue;
		} else {
			unsigned two_pow_sppr;
			/*
			 * Find the highest bit set in divider. This and the
			 * three next bits define SPR (apart from rounding).
			 * SPPR is then the number of zero bits that must be
			 * appended:
			 */
			sppr = fls(divider) - 4;

			clk = tclk_hz / (spr * sppr2);
			err = speed - clk;
			/*
			 * As SPR only has 4 bits, we have to round divider up
			 * to the next multiple of 2 ** sppr.
			 */
			two_pow_sppr = 1 << sppr;
			divider = (divider + two_pow_sppr - 1) & -two_pow_sppr;

			if (err < best_err) {
				best_spr = spr;
				best_sppr = sppr;
				best_err = err;
			}
		}
			/*
			 * recalculate sppr as rounding up divider might have
			 * increased it enough to change the position of the
			 * highest set bit. In this case the bit that now
			 * doesn't make it into SPR is 0, so there is no need to
			 * round again.
			 */
			sppr = fls(divider) - 4;
			spr = divider >> sppr;

		if ((best_sppr == 0) && (best_spr == 0))
			/*
			 * Now do range checking. SPR is constructed to have a
			 * width of 4 bits, so this is fine for sure. So we
			 * still need to check for sppr to fit into 3 bits:
			 */
			if (sppr > 7)
				return -EINVAL;
		}

		prescale = ((best_sppr & 0x6) << 5) |
			((best_sppr & 0x1) << 4) | best_spr;
		prescale = ((sppr & 0x6) << 5) | ((sppr & 0x1) << 4) | spr;
	} else {
		/*
		 * the supported rates are: 4,6,8...30
+1 −1
Original line number Diff line number Diff line
@@ -315,7 +315,7 @@ static void transfer_file(int fd, char *filename)
		pabort("can't stat input file");

	tx_fd = open(filename, O_RDONLY);
	if (fd < 0)
	if (tx_fd < 0)
		pabort("can't open input file");

	tx = malloc(sb.st_size);