#include <spi.h>
#include <clk.h>
#include <wait_bit.h>
+#include <asm/global_data.h>
#include <asm/io.h>
#include <dm/device_compat.h>
#include <linux/bitops.h>
+#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
#define MVEBU_SPI_A3700_SPI_EN_0 BIT(16)
#define MVEBU_SPI_A3700_CLK_PRESCALE_MASK 0x1f
+#define MAX_CS_COUNT 4
/* SPI registers */
struct spi_reg {
u32 din; /* 0x1060c */
};
-struct mvebu_spi_platdata {
+struct mvebu_spi_plat {
struct spi_reg *spireg;
struct clk clk;
+ struct gpio_desc cs_gpios[MAX_CS_COUNT];
};
-static void spi_cs_activate(struct spi_reg *reg, int cs)
+static void spi_cs_activate(struct mvebu_spi_plat *plat, int cs)
{
- setbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
+ if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&plat->cs_gpios[cs]))
+ dm_gpio_set_value(&plat->cs_gpios[cs], 1);
+ else
+ setbits_le32(&plat->spireg->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
}
-static void spi_cs_deactivate(struct spi_reg *reg, int cs)
+static void spi_cs_deactivate(struct mvebu_spi_plat *plat, int cs)
{
- clrbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
+ if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&plat->cs_gpios[cs]))
+ dm_gpio_set_value(&plat->cs_gpios[cs], 0);
+ else
+ clrbits_le32(&plat->spireg->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
}
/**
const void *dout, void *din, unsigned long flags)
{
struct udevice *bus = dev->parent;
- struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+ struct mvebu_spi_plat *plat = dev_get_plat(bus);
struct spi_reg *reg = plat->spireg;
unsigned int bytelen;
int ret;
/* Activate CS */
if (flags & SPI_XFER_BEGIN) {
debug("SPI: activate cs.\n");
- spi_cs_activate(reg, spi_chip_select(dev));
+ spi_cs_activate(plat, spi_chip_select(dev));
}
/* Send and/or receive */
return ret;
debug("SPI: deactivate cs.\n");
- spi_cs_deactivate(reg, spi_chip_select(dev));
+ spi_cs_deactivate(plat, spi_chip_select(dev));
}
return 0;
static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
{
- struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+ struct mvebu_spi_plat *plat = dev_get_plat(bus);
struct spi_reg *reg = plat->spireg;
u32 data, prescale;
static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
{
- struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+ struct mvebu_spi_plat *plat = dev_get_plat(bus);
struct spi_reg *reg = plat->spireg;
/*
static int mvebu_spi_probe(struct udevice *bus)
{
- struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+ struct mvebu_spi_plat *plat = dev_get_plat(bus);
struct spi_reg *reg = plat->spireg;
u32 data;
int ret;
writel(data, ®->cfg);
+ /* Set up CS GPIOs in device tree, if any */
+ if (CONFIG_IS_ENABLED(DM_GPIO) && gpio_get_list_count(bus, "cs-gpios") > 0) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(plat->cs_gpios); i++) {
+ ret = gpio_request_by_name(bus, "cs-gpios", i, &plat->cs_gpios[i], 0);
+ if (ret < 0 || !dm_gpio_is_valid(&plat->cs_gpios[i])) {
+ /* Use the native CS function for this line */
+ continue;
+ }
+
+ ret = dm_gpio_set_dir_flags(&plat->cs_gpios[i],
+ GPIOD_IS_OUT | GPIOD_ACTIVE_LOW);
+ if (ret) {
+ dev_err(bus, "Setting cs %d error\n", i);
+ return ret;
+ }
+ }
+ }
+
return 0;
}
-static int mvebu_spi_ofdata_to_platdata(struct udevice *bus)
+static int mvebu_spi_of_to_plat(struct udevice *bus)
{
- struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+ struct mvebu_spi_plat *plat = dev_get_plat(bus);
int ret;
- plat->spireg = (struct spi_reg *)devfdt_get_addr(bus);
+ plat->spireg = dev_read_addr_ptr(bus);
ret = clk_get_by_index(bus, 0, &plat->clk);
if (ret) {
static int mvebu_spi_remove(struct udevice *bus)
{
- struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+ struct mvebu_spi_plat *plat = dev_get_plat(bus);
clk_free(&plat->clk);
.id = UCLASS_SPI,
.of_match = mvebu_spi_ids,
.ops = &mvebu_spi_ops,
- .ofdata_to_platdata = mvebu_spi_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct mvebu_spi_platdata),
+ .of_to_plat = mvebu_spi_of_to_plat,
+ .plat_auto = sizeof(struct mvebu_spi_plat),
.probe = mvebu_spi_probe,
.remove = mvebu_spi_remove,
};