Commit b14a8a80 authored by Mark Brown's avatar Mark Brown

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

...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -295,6 +296,7 @@ struct atmel_spi { ...@@ -295,6 +296,7 @@ struct atmel_spi {
int irq; int irq;
struct clk *clk; struct clk *clk;
struct platform_device *pdev; struct platform_device *pdev;
unsigned long spi_clk;
struct spi_transfer *current_transfer; struct spi_transfer *current_transfer;
int current_remaining_bytes; int current_remaining_bytes;
...@@ -864,7 +866,7 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as, ...@@ -864,7 +866,7 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
unsigned long bus_hz; unsigned long bus_hz;
/* v1 chips start out at half the peripheral bus speed. */ /* 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)) if (!atmel_spi_is_v2(as))
bus_hz /= 2; bus_hz /= 2;
...@@ -1204,7 +1206,6 @@ static int atmel_spi_setup(struct spi_device *spi) ...@@ -1204,7 +1206,6 @@ static int atmel_spi_setup(struct spi_device *spi)
u32 csr; u32 csr;
unsigned int bits = spi->bits_per_word; unsigned int bits = spi->bits_per_word;
unsigned int npcs_pin; unsigned int npcs_pin;
int ret;
as = spi_master_get_devdata(spi->master); as = spi_master_get_devdata(spi->master);
...@@ -1247,16 +1248,9 @@ static int atmel_spi_setup(struct spi_device *spi) ...@@ -1247,16 +1248,9 @@ static int atmel_spi_setup(struct spi_device *spi)
if (!asd) if (!asd)
return -ENOMEM; return -ENOMEM;
if (as->use_cs_gpios) { 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, gpio_direction_output(npcs_pin,
!(spi->mode & SPI_CS_HIGH)); !(spi->mode & SPI_CS_HIGH));
}
asd->npcs_pin = npcs_pin; asd->npcs_pin = npcs_pin;
spi->controller_state = asd; spi->controller_state = asd;
...@@ -1471,13 +1465,11 @@ static int atmel_spi_transfer_one_message(struct spi_master *master, ...@@ -1471,13 +1465,11 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
static void atmel_spi_cleanup(struct spi_device *spi) static void atmel_spi_cleanup(struct spi_device *spi)
{ {
struct atmel_spi_device *asd = spi->controller_state; struct atmel_spi_device *asd = spi->controller_state;
unsigned gpio = (unsigned long) spi->controller_data;
if (!asd) if (!asd)
return; return;
spi->controller_state = NULL; spi->controller_state = NULL;
gpio_free(gpio);
kfree(asd); kfree(asd);
} }
...@@ -1499,6 +1491,39 @@ static void atmel_get_caps(struct atmel_spi *as) ...@@ -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) static int atmel_spi_probe(struct platform_device *pdev)
{ {
...@@ -1577,6 +1602,10 @@ 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; master->num_chipselect = 4;
} }
ret = atmel_spi_gpio_cs(pdev);
if (ret)
goto out_unmap_regs;
as->use_dma = false; as->use_dma = false;
as->use_pdc = false; as->use_pdc = false;
if (as->caps.has_dma_support) { if (as->caps.has_dma_support) {
...@@ -1606,6 +1635,9 @@ static int atmel_spi_probe(struct platform_device *pdev) ...@@ -1606,6 +1635,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
ret = clk_prepare_enable(clk); ret = clk_prepare_enable(clk);
if (ret) if (ret)
goto out_free_irq; 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));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
if (as->caps.has_wdrbt) { if (as->caps.has_wdrbt) {
......
...@@ -138,37 +138,62 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) ...@@ -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); tclk_hz = clk_get_rate(orion_spi->clk);
if (devdata->typ == ARMADA_SPI) { 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
best_err = speed; * [0..7]) such that
best_spr = 0; *
best_sppr = 0; * core_clk / (SPR * 2 ** SPPR)
*
/* Iterate over the valid range looking for best fit */ * is as big as possible but not bigger than speed.
for (sppr = 0; sppr < 8; sppr++) { */
sppr2 = 0x1 << sppr;
spr = tclk_hz / sppr2;
spr = DIV_ROUND_UP(spr, speed);
if ((spr == 0) || (spr > 15))
continue;
clk = tclk_hz / (spr * sppr2);
err = speed - clk;
if (err < best_err) {
best_spr = spr;
best_sppr = sppr;
best_err = err;
}
}
if ((best_sppr == 0) && (best_spr == 0)) /* best integer divider: */
return -EINVAL; unsigned divider = DIV_ROUND_UP(tclk_hz, speed);
unsigned spr, sppr;
if (divider < 16) {
/* This is the easy case, divider is less than 16 */
spr = divider;
sppr = 0;
} 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;
/*
* 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;
/*
* 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;
/*
* 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) | prescale = ((sppr & 0x6) << 5) | ((sppr & 0x1) << 4) | spr;
((best_sppr & 0x1) << 4) | best_spr;
} else { } else {
/* /*
* the supported rates are: 4,6,8...30 * the supported rates are: 4,6,8...30
......
...@@ -315,7 +315,7 @@ static void transfer_file(int fd, char *filename) ...@@ -315,7 +315,7 @@ static void transfer_file(int fd, char *filename)
pabort("can't stat input file"); pabort("can't stat input file");
tx_fd = open(filename, O_RDONLY); tx_fd = open(filename, O_RDONLY);
if (fd < 0) if (tx_fd < 0)
pabort("can't open input file"); pabort("can't open input file");
tx = malloc(sb.st_size); tx = malloc(sb.st_size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment