mirror of
https://github.com/torvalds/linux.git
synced 2024-11-05 19:41:54 +00:00
Merge remote-tracking branches 'spi/fix/atmel', 'spi/fix/mvbeu' and 'spi/fix/spidev' into spi-linus
This commit is contained in:
commit
b14a8a8028
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
if ((best_sppr == 0) && (best_spr == 0))
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user