Skip to content

Commit

Permalink
Merge remote-tracking branches 'spi/fix/atmel', 'spi/fix/mvbeu' and '…
Browse files Browse the repository at this point in the history
…spi/fix/spidev' into spi-linus
  • Loading branch information
Mark Brown committed Dec 12, 2016
4 parents 69973b8 + 39fe33f + 7243e0b + e634b76 commit b14a8a8
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 42 deletions.
56 changes: 44 additions & 12 deletions drivers/spi/spi-atmel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand All @@ -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)
{
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
83 changes: 54 additions & 29 deletions drivers/spi/spi-orion.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tools/spi/spidev_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit b14a8a8

Please sign in to comment.