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 @@
#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 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
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) {
......
......@@ -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;
best_err = speed;
best_spr = 0;
best_sppr = 0;
/* Iterate over the valid range looking for best fit */
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;
}
}
/*
* 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.
*/
if ((best_sppr == 0) && (best_spr == 0))
return -EINVAL;
/* best integer divider: */
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) |
((best_sppr & 0x1) << 4) | best_spr;
prescale = ((sppr & 0x6) << 5) | ((sppr & 0x1) << 4) | spr;
} else {
/*
* the supported rates are: 4,6,8...30
......
......@@ -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);
......
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