Aleksandar Markovic <aleksandar.markovic@mips.com> <aleksandar.markovic@imgtec.com>
Al Viro <viro@ftp.linux.org.uk>
Al Viro <viro@zenIV.linux.org.uk>
+Andi Shyti <andi@etezian.org> <andi.shyti@samsung.com>
Andreas Herrmann <aherrman@de.ibm.com>
Andrey Ryabinin <ryabinin.a.a@gmail.com> <a.ryabinin@samsung.com>
Andrew Morton <akpm@linux-foundation.org>
"renesas,msiof-r8a7794" (R-Car E2)
"renesas,msiof-r8a7795" (R-Car H3)
"renesas,msiof-r8a7796" (R-Car M3-W)
+ "renesas,msiof-r8a77965" (R-Car M3-N)
"renesas,msiof-sh73a0" (SH-Mobile AG5)
"renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device)
"renesas,rcar-gen2-msiof" (generic R-Car Gen2 and RZ/G1 compatible device)
SPI-GPIO devicetree bindings
+This represents a group of 3-n GPIO lines used for bit-banged SPI on dedicated
+GPIO lines.
+
Required properties:
- compatible: should be set to "spi-gpio"
- #address-cells: should be set to <0x1>
- ranges
- - gpio-sck: GPIO spec for the SCK line to use
- - gpio-miso: GPIO spec for the MISO line to use
- - gpio-mosi: GPIO spec for the MOSI line to use
+ - sck-gpios: GPIO spec for the SCK line to use
+ - miso-gpios: GPIO spec for the MISO line to use
+ - mosi-gpios: GPIO spec for the MOSI line to use
- cs-gpios: GPIOs to use for chipselect lines.
Not needed if num-chipselects = <0>.
- num-chipselects: Number of chipselect lines. Should be <0> if a single device
with no chip select is connected.
+Deprecated bindings:
+
+These legacy GPIO line bindings can alternatively be used to define the
+GPIO lines used, they should not be used in new device trees.
+
+ - gpio-sck: GPIO spec for the SCK line to use
+ - gpio-miso: GPIO spec for the MISO line to use
+ - gpio-mosi: GPIO spec for the MOSI line to use
+
Example:
spi {
#address-cells = <0x1>;
ranges;
- gpio-sck = <&gpio 95 0>;
- gpio-miso = <&gpio 98 0>;
- gpio-mosi = <&gpio 97 0>;
+ sck-gpios = <&gpio 95 0>;
+ miso-gpios = <&gpio 98 0>;
+ mosi-gpios = <&gpio 97 0>;
cs-gpios = <&gpio 125 0>;
num-chipselects = <1>;
SAMSUNG SPI DRIVERS
M: Kukjin Kim <kgene@kernel.org>
M: Krzysztof Kozlowski <krzk@kernel.org>
-M: Andi Shyti <andi.shyti@samsung.com>
+M: Andi Shyti <andi@etezian.org>
L: linux-spi@vger.kernel.org
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/dm9000.h>
#include <linux/leds.h>
#include <linux/platform_data/rtc-v3020.h>
#define LCD_SPI_BUS_NUM (1)
static struct spi_gpio_platform_data cm_x300_spi_gpio_pdata = {
- .sck = GPIO_LCD_SCL,
- .mosi = GPIO_LCD_DIN,
- .miso = GPIO_LCD_DOUT,
.num_chipselect = 1,
};
},
};
+static struct gpiod_lookup_table cm_x300_spi_gpiod_table = {
+ .dev_id = "spi_gpio",
+ .table = {
+ GPIO_LOOKUP("gpio-pxa", GPIO_LCD_SCL,
+ "sck", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DIN,
+ "mosi", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DOUT,
+ "miso", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio-pxa", GPIO_LCD_CS,
+ "cs", GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
static struct tdo24m_platform_data cm_x300_tdo24m_pdata = {
.model = TDO35S,
};
.max_speed_hz = 1000000,
.bus_num = LCD_SPI_BUS_NUM,
.chip_select = 0,
- .controller_data = (void *) GPIO_LCD_CS,
.platform_data = &cm_x300_tdo24m_pdata,
},
};
{
spi_register_board_info(cm_x300_spi_devices,
ARRAY_SIZE(cm_x300_spi_devices));
+ gpiod_add_lookup_table(&cm_x300_spi_gpiod_table);
platform_device_register(&cm_x300_spi_gpio);
}
#else
*/
static struct spi_gpio_platform_data raumfeld_spi_platform_data = {
- .sck = GPIO_SPI_CLK,
- .mosi = GPIO_SPI_MOSI,
- .miso = GPIO_SPI_MISO,
.num_chipselect = 3,
};
}
};
+static struct gpiod_lookup_table raumfeld_spi_gpiod_table = {
+ .dev_id = "spi_gpio",
+ .table = {
+ GPIO_LOOKUP("gpio-0", GPIO_SPI_CLK,
+ "sck", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio-0", GPIO_SPI_MOSI,
+ "mosi", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio-0", GPIO_SPI_MISO,
+ "miso", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP_IDX("gpio-0", GPIO_SPDIF_CS,
+ "cs", 0, GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP_IDX("gpio-0", GPIO_ACCEL_CS,
+ "cs", 1, GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP_IDX("gpio-0", GPIO_MCLK_DAC_CS,
+ "cs", 2, GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
static struct lis3lv02d_platform_data lis3_pdata = {
.click_flags = LIS3_CLICK_SINGLE_X |
LIS3_CLICK_SINGLE_Y |
.max_speed_hz = 10000, \
.bus_num = 0, \
.chip_select = 0, \
- .controller_data = (void *) GPIO_SPDIF_CS, \
}
#define SPI_LIS3 \
.max_speed_hz = 1000000, \
.bus_num = 0, \
.chip_select = 1, \
- .controller_data = (void *) GPIO_ACCEL_CS, \
.platform_data = &lis3_pdata, \
.irq = PXA_GPIO_TO_IRQ(GPIO_ACCEL_IRQ), \
}
.max_speed_hz = 1000000, \
.bus_num = 0, \
.chip_select = 2, \
- .controller_data = (void *) GPIO_MCLK_DAC_CS, \
}
static struct spi_board_info connector_spi_devices[] __initdata = {
else
gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0);
+ gpiod_add_lookup_table(&raumfeld_spi_gpiod_table);
platform_add_devices(ARRAY_AND_SIZE(raumfeld_common_devices));
i2c_register_board_info(1, &raumfeld_pwri2c_board_info, 1);
}
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/syscore_ops.h>
#include <linux/serial_core.h>
#include <linux/serial_s3c.h>
/* LCD SPI support */
static struct spi_gpio_platform_data jive_lcd_spi = {
- .sck = S3C2410_GPG(8),
- .mosi = S3C2410_GPB(8),
- .miso = SPI_GPIO_NO_MISO,
+ .num_chipselect = 1,
};
static struct platform_device jive_device_lcdspi = {
- .name = "spi-gpio",
+ .name = "spi_gpio",
.id = 1,
.dev.platform_data = &jive_lcd_spi,
};
+static struct gpiod_lookup_table jive_lcdspi_gpiod_table = {
+ .dev_id = "spi_gpio",
+ .table = {
+ GPIO_LOOKUP("GPIOG", 8,
+ "sck", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOB", 8,
+ "mosi", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOB", 7,
+ "cs", GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
/* WM8750 audio code SPI definition */
static struct spi_gpio_platform_data jive_wm8750_spi = {
- .sck = S3C2410_GPB(4),
- .mosi = S3C2410_GPB(9),
- .miso = SPI_GPIO_NO_MISO,
+ .num_chipselect = 1,
};
static struct platform_device jive_device_wm8750 = {
- .name = "spi-gpio",
+ .name = "spi_gpio",
.id = 2,
.dev.platform_data = &jive_wm8750_spi,
};
+static struct gpiod_lookup_table jive_wm8750_gpiod_table = {
+ .dev_id = "spi_gpio",
+ .table = {
+ GPIO_LOOKUP("GPIOB", 4,
+ "gpio-sck", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOB", 9,
+ "gpio-mosi", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOH", 10,
+ "cs", GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
/* JIVE SPI devices. */
static struct spi_board_info __initdata jive_spi_devs[] = {
.mode = SPI_MODE_3, /* CPOL=1, CPHA=1 */
.max_speed_hz = 100000,
.platform_data = &jive_lcm_config,
- .controller_data = (void *)S3C2410_GPB(7),
}, {
.modalias = "WM8750",
.bus_num = 2,
.chip_select = 0,
.mode = SPI_MODE_0, /* CPOL=0, CPHA=0 */
.max_speed_hz = 100000,
- .controller_data = (void *)S3C2410_GPH(10),
},
};
/** TODO - check that this is after the cmdline option! */
s3c_nand_set_platdata(&jive_nand_info);
- /* initialise the spi */
-
gpio_request(S3C2410_GPG(13), "lcm reset");
gpio_direction_output(S3C2410_GPG(13), 0);
- gpio_request(S3C2410_GPB(7), "jive spi");
- gpio_direction_output(S3C2410_GPB(7), 1);
-
gpio_request_one(S3C2410_GPB(6), GPIOF_OUT_INIT_LOW, NULL);
gpio_free(S3C2410_GPB(6));
- gpio_request_one(S3C2410_GPG(8), GPIOF_OUT_INIT_HIGH, NULL);
- gpio_free(S3C2410_GPG(8));
-
- /* initialise the WM8750 spi */
-
- gpio_request(S3C2410_GPH(10), "jive wm8750 spi");
- gpio_direction_output(S3C2410_GPH(10), 1);
-
/* Turn off suspend on both USB ports, and switch the
* selectable USB port to USB device mode. */
pm_power_off = jive_power_off;
+ gpiod_add_lookup_table(&jive_lcdspi_gpiod_table);
+ gpiod_add_lookup_table(&jive_wm8750_gpiod_table);
platform_add_devices(jive_devices, ARRAY_SIZE(jive_devices));
}
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
/* SPI */
static struct spi_gpio_platform_data spi_gpio_cfg = {
- .sck = S3C2410_GPG(7),
- .mosi = S3C2410_GPG(6),
- .miso = S3C2410_GPG(5),
+ .num_chipselect = 1,
};
static struct platform_device qt2410_spi = {
- .name = "spi-gpio",
+ .name = "spi_gpio",
.id = 1,
.dev.platform_data = &spi_gpio_cfg,
};
+static struct gpiod_lookup_table qt2410_spi_gpiod_table = {
+ .dev_id = "spi_gpio",
+ .table = {
+ GPIO_LOOKUP("GPIOG", 7,
+ "sck", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOG", 6,
+ "mosi", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOG", 5,
+ "miso", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOB", 5,
+ "cs", GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
/* Board devices */
static struct platform_device *qt2410_devices[] __initdata = {
s3c24xx_udc_set_platdata(&qt2410_udc_cfg);
s3c_i2c0_set_platdata(NULL);
- WARN_ON(gpio_request(S3C2410_GPB(5), "spi cs"));
- gpio_direction_output(S3C2410_GPB(5), 1);
-
+ gpiod_add_lookup_table(&qt2410_spi_gpiod_table);
platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices));
s3c_pm_init();
}
/* GPM0 -> CS */
static struct spi_gpio_platform_data smartq_lcd_control = {
- .sck = S3C64XX_GPM(1),
- .mosi = S3C64XX_GPM(2),
- .miso = S3C64XX_GPM(2),
+ .num_chipselect = 1,
};
static struct platform_device smartq_lcd_control_device = {
- .name = "spi-gpio",
+ .name = "spi_gpio",
.id = 1,
.dev.platform_data = &smartq_lcd_control,
};
+static struct gpiod_lookup_table smartq_lcd_control_gpiod_table = {
+ .dev_id = "spi_gpio",
+ .table = {
+ GPIO_LOOKUP("GPIOM", 1,
+ "sck", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOM", 2,
+ "mosi", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOM", 3,
+ "miso", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOM", 0,
+ "cs", GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
static void smartq_lcd_power_set(struct plat_lcd_data *pd, unsigned int power)
{
gpio_direction_output(S3C64XX_GPM(3), power);
WARN_ON(smartq_wifi_init());
pwm_add_table(smartq_pwm_lookup, ARRAY_SIZE(smartq_pwm_lookup));
+ gpiod_add_lookup_table(&smartq_lcd_control_gpiod_table);
platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices));
gpiod_add_lookup_table(&smartq_audio_gpios);
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/leds.h>
};
static struct spi_gpio_platform_data db1100_spictl_pd = {
- .sck = 209,
- .mosi = 208,
- .miso = 207,
.num_chipselect = 1,
};
.mode = 0,
.irq = AU1100_GPIO21_INT,
.platform_data = &db1100_touch_pd,
- .controller_data = (void *)210, /* for spi_gpio: CS# GPIO210 */
},
};
},
};
+/*
+ * Alchemy GPIO 2 has its base at 200 so the GPIO lines
+ * 207 thru 210 are GPIOs at offset 7 thru 10 at this chip.
+ */
+static struct gpiod_lookup_table db1100_spi_gpiod_table = {
+ .dev_id = "spi_gpio",
+ .table = {
+ GPIO_LOOKUP("alchemy-gpio2", 9,
+ "sck", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("alchemy-gpio2", 8,
+ "mosi", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("alchemy-gpio2", 7,
+ "miso", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("alchemy-gpio2", 10,
+ "cs", GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
static struct platform_device *db1x00_devs[] = {
&db1x00_codec_dev,
clk_put(p);
platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs));
+ gpiod_add_lookup_table(&db1100_spi_gpiod_table);
platform_device_register(&db1100_spi_dev);
} else if (board == BCSR_WHOAMI_DB1000) {
c0 = AU1000_GPIO2_INT;
.pixclk_falling_edge = 1,
};
-struct spi_gpio_platform_data spigpio_platform_data = {
- .sck = JZ_GPIO_PORTC(23),
- .mosi = JZ_GPIO_PORTC(22),
- .miso = -1,
+struct spi_gpio_platform_data qi_lb60_spigpio_platform_data = {
.num_chipselect = 1,
};
-static struct platform_device spigpio_device = {
+static struct platform_device qi_lb60_spigpio_device = {
.name = "spi_gpio",
.id = 1,
.dev = {
- .platform_data = &spigpio_platform_data,
+ .platform_data = &qi_lb60_spigpio_platform_data,
+ },
+};
+
+static struct gpiod_lookup_table qi_lb60_spigpio_gpio_table = {
+ .dev_id = "spi_gpio",
+ .table = {
+ GPIO_LOOKUP("GPIOC", 23,
+ "sck", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOC", 22,
+ "mosi", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("GPIOC", 21,
+ "cs", GPIO_ACTIVE_HIGH),
+ { },
},
};
static struct spi_board_info qi_lb60_spi_board_info[] = {
{
.modalias = "ili8960",
- .controller_data = (void *)JZ_GPIO_PORTC(21),
.chip_select = 0,
.bus_num = 1,
.max_speed_hz = 30 * 1000,
&jz4740_mmc_device,
&jz4740_nand_device,
&qi_lb60_keypad,
- &spigpio_device,
+ &qi_lb60_spigpio_device,
&jz4740_framebuffer_device,
&jz4740_pcm_device,
&jz4740_i2s_device,
gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
gpiod_add_lookup_table(&qi_lb60_nand_gpio_table);
+ gpiod_add_lookup_table(&qi_lb60_spigpio_gpio_table);
spi_register_board_info(qi_lb60_spi_board_info,
ARRAY_SIZE(qi_lb60_spi_board_info));
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
+ *
+ * FIXME: this driver is used on a device-tree probed platform: it
+ * should be defined as a bit-banged SPI device and probed from the device
+ * tree and not like this with static grabbing of a few numbered GPIO
+ * lines at random.
+ *
+ * Add proper SPI and EEPROM in arch/powerpc/boot/dts/digsy_mtc.dts
+ * and delete this driver.
*/
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
};
static struct spi_gpio_platform_data eeprom_spi_gpio_data = {
- .sck = GPIO_EEPROM_CLK,
- .mosi = GPIO_EEPROM_DI,
- .miso = GPIO_EEPROM_DO,
.num_chipselect = 1,
};
},
};
+static struct gpiod_lookup_table eeprom_spi_gpiod_table = {
+ .dev_id = "spi_gpio",
+ .table = {
+ GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_CLK,
+ "sck", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_DI,
+ "mosi", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_DO,
+ "miso", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_CS,
+ "cs", GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = {
{
.modalias = "93xx46",
.bus_num = EE_SPI_BUS_NUM,
.chip_select = 0,
.mode = SPI_MODE_0,
- .controller_data = (void *)GPIO_EEPROM_CS,
.platform_data = &digsy_mtc_eeprom_data,
},
};
pr_err("can't request gpio %d\n", GPIO_EEPROM_OE);
return ret;
}
+ gpiod_add_lookup_table(&eeprom_spi_gpiod_table);
spi_register_board_info(digsy_mtc_eeprom_info,
ARRAY_SIZE(digsy_mtc_eeprom_info));
return platform_device_register(&digsy_mtc_eeprom);
rxdesc = dmaengine_prep_slave_single(rxchan,
as->dma_addr_rx_bbuf,
xfer->len,
- DMA_FROM_DEVICE,
+ DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
} else {
rxdesc = dmaengine_prep_slave_sg(rxchan,
xfer->rx_sg.sgl,
xfer->rx_sg.nents,
- DMA_FROM_DEVICE,
+ DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
}
memcpy(as->addr_tx_bbuf, xfer->tx_buf, xfer->len);
txdesc = dmaengine_prep_slave_single(txchan,
as->dma_addr_tx_bbuf,
- xfer->len, DMA_TO_DEVICE,
+ xfer->len, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
} else {
txdesc = dmaengine_prep_slave_sg(txchan,
xfer->tx_sg.sgl,
xfer->tx_sg.nents,
- DMA_TO_DEVICE,
+ DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
}
{
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
+
+ /* It is recommended to enable FIFOs first thing after reset */
+ if (as->fifo_size)
+ spi_writel(as, CR, SPI_BIT(FIFOEN));
+
if (as->caps.has_wdrbt) {
spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS)
| SPI_BIT(MSTR));
if (as->use_pdc)
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
spi_writel(as, CR, SPI_BIT(SPIEN));
-
- if (as->fifo_size)
- spi_writel(as, CR, SPI_BIT(FIFOEN));
}
static int atmel_spi_probe(struct platform_device *pdev)
qspi->base[MSPI] = devm_ioremap_resource(dev, res);
if (IS_ERR(qspi->base[MSPI])) {
ret = PTR_ERR(qspi->base[MSPI]);
- goto qspi_probe_err;
+ goto qspi_resource_err;
}
} else {
goto qspi_resource_err;
qspi->base[BSPI] = devm_ioremap_resource(dev, res);
if (IS_ERR(qspi->base[BSPI])) {
ret = PTR_ERR(qspi->base[BSPI]);
- goto qspi_probe_err;
+ goto qspi_resource_err;
}
qspi->bspi_mode = true;
} else {
struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
unsigned long spi_hz, clk_hz, speed;
unsigned long spi_used_hz;
- unsigned long long xfer_time_us;
/* calculate the registers to handle
*
bs->rx_len = tfr->len;
bs->pending = 0;
- /* calculate the estimated time in us the transfer runs
- * note that there are are 2 idle clocks after each
- * chunk getting transferred - in our case the chunk size
- * is 3 bytes, so we approximate this by 9 bits/byte
+ /* Calculate the estimated time in us the transfer runs. Note that
+ * there are are 2 idle clocks cycles after each chunk getting
+ * transferred - in our case the chunk size is 3 bytes, so we
+ * approximate this by 9 cycles/byte. This is used to find the number
+ * of Hz per byte per polling limit. E.g., we can transfer 1 byte in
+ * 30 µs per 300,000 Hz of bus clock.
*/
- xfer_time_us = tfr->len * 9 * 1000000;
- do_div(xfer_time_us, spi_used_hz);
-
+#define HZ_PER_BYTE ((9 * 1000000) / BCM2835_AUX_SPI_POLLING_LIMIT_US)
/* run in polling mode for short transfers */
- if (xfer_time_us < BCM2835_AUX_SPI_POLLING_LIMIT_US)
+ if (tfr->len < spi_used_hz / HZ_PER_BYTE)
return bcm2835aux_spi_transfer_one_poll(master, spi, tfr);
/* run in interrupt mode for all others */
return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
+#undef HZ_PER_BYTE
}
static int bcm2835aux_spi_prepare_message(struct spi_master *master,
return IRQ_HANDLED;
}
-static bool mid_spi_can_dma(struct spi_master *master, struct spi_device *spi,
- struct spi_transfer *xfer)
+static bool mid_spi_can_dma(struct spi_controller *master,
+ struct spi_device *spi, struct spi_transfer *xfer)
{
- struct dw_spi *dws = spi_master_get_devdata(master);
+ struct dw_spi *dws = spi_controller_get_devdata(master);
if (!dws->dma_inited)
return false;
static void dw_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct dw_spi *dws = spi_master_get_devdata(spi->master);
+ struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
struct chip_data *chip = spi_get_ctldata(spi);
/* Chip select logic is inverted from spi_set_cs() */
static irqreturn_t dw_spi_irq(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
- struct dw_spi *dws = spi_master_get_devdata(master);
+ struct spi_controller *master = dev_id;
+ struct dw_spi *dws = spi_controller_get_devdata(master);
u16 irq_status = dw_readl(dws, DW_SPI_ISR) & 0x3f;
if (!irq_status)
return 0;
}
-static int dw_spi_transfer_one(struct spi_master *master,
+static int dw_spi_transfer_one(struct spi_controller *master,
struct spi_device *spi, struct spi_transfer *transfer)
{
- struct dw_spi *dws = spi_master_get_devdata(master);
+ struct dw_spi *dws = spi_controller_get_devdata(master);
struct chip_data *chip = spi_get_ctldata(spi);
u8 imask = 0;
u16 txlevel = 0;
return 1;
}
-static void dw_spi_handle_err(struct spi_master *master,
+static void dw_spi_handle_err(struct spi_controller *master,
struct spi_message *msg)
{
- struct dw_spi *dws = spi_master_get_devdata(master);
+ struct dw_spi *dws = spi_controller_get_devdata(master);
if (dws->dma_mapped)
dws->dma_ops->dma_stop(dws);
int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
{
- struct spi_master *master;
+ struct spi_controller *master;
int ret;
BUG_ON(dws == NULL);
}
}
- spi_master_set_devdata(master, dws);
- ret = devm_spi_register_master(dev, master);
+ spi_controller_set_devdata(master, dws);
+ ret = devm_spi_register_controller(dev, master);
if (ret) {
dev_err(&master->dev, "problem registering spi master\n");
goto err_dma_exit;
spi_enable_chip(dws, 0);
free_irq(dws->irq, master);
err_free_master:
- spi_master_put(master);
+ spi_controller_put(master);
return ret;
}
EXPORT_SYMBOL_GPL(dw_spi_add_host);
{
int ret;
- ret = spi_master_suspend(dws->master);
+ ret = spi_controller_suspend(dws->master);
if (ret)
return ret;
int ret;
spi_hw_init(&dws->master->dev, dws);
- ret = spi_master_resume(dws->master);
+ ret = spi_controller_resume(dws->master);
if (ret)
dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
return ret;
int (*dma_init)(struct dw_spi *dws);
void (*dma_exit)(struct dw_spi *dws);
int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer);
- bool (*can_dma)(struct spi_master *master, struct spi_device *spi,
+ bool (*can_dma)(struct spi_controller *master, struct spi_device *spi,
struct spi_transfer *xfer);
int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer);
void (*dma_stop)(struct dw_spi *dws);
};
struct dw_spi {
- struct spi_master *master;
+ struct spi_controller *master;
enum dw_ssi_type type;
void __iomem *regs;
* SPI master driver using generic bitbanged GPIO
*
* Copyright (C) 2006,2008 David Brownell
+ * Copyright (C) 2017 Linus Walleij
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
struct spi_bitbang bitbang;
struct spi_gpio_platform_data pdata;
struct platform_device *pdev;
- unsigned long cs_gpios[0];
+ struct gpio_desc *sck;
+ struct gpio_desc *miso;
+ struct gpio_desc *mosi;
+ struct gpio_desc **cs_gpios;
+ bool has_cs;
};
/*----------------------------------------------------------------------*/
#define GENERIC_BITBANG /* vs tight inlines */
-/* all functions referencing these symbols must define pdata */
-#define SPI_MISO_GPIO ((pdata)->miso)
-#define SPI_MOSI_GPIO ((pdata)->mosi)
-#define SPI_SCK_GPIO ((pdata)->sck)
-
-#define SPI_N_CHIPSEL ((pdata)->num_chipselect)
-
#endif
/*----------------------------------------------------------------------*/
return &spi_to_spi_gpio(spi)->pdata;
}
-/* this is #defined to avoid unused-variable warnings when inlining */
-#define pdata spi_to_pdata(spi)
-
+/* These helpers are in turn called by the bitbang inlines */
static inline void setsck(const struct spi_device *spi, int is_on)
{
- gpio_set_value_cansleep(SPI_SCK_GPIO, is_on);
+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+
+ gpiod_set_value_cansleep(spi_gpio->sck, is_on);
}
static inline void setmosi(const struct spi_device *spi, int is_on)
{
- gpio_set_value_cansleep(SPI_MOSI_GPIO, is_on);
+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+
+ gpiod_set_value_cansleep(spi_gpio->mosi, is_on);
}
static inline int getmiso(const struct spi_device *spi)
{
- return !!gpio_get_value_cansleep(SPI_MISO_GPIO);
-}
+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
-#undef pdata
+ return !!gpiod_get_value_cansleep(spi_gpio->miso);
+}
/*
* NOTE: this clocks "as fast as we can". It "should" be a function of the
static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
{
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
- unsigned long cs = spi_gpio->cs_gpios[spi->chip_select];
- /* set initial clock polarity */
+ /* set initial clock line level */
if (is_active)
- setsck(spi, spi->mode & SPI_CPOL);
+ gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL);
+
+ /* Drive chip select line, if we have one */
+ if (spi_gpio->has_cs) {
+ struct gpio_desc *cs = spi_gpio->cs_gpios[spi->chip_select];
- if (cs != SPI_GPIO_NO_CHIPSELECT) {
- /* SPI is normally active-low */
- gpio_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
+ /* SPI chip selects are normally active-low */
+ gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
}
}
static int spi_gpio_setup(struct spi_device *spi)
{
- unsigned long cs;
+ struct gpio_desc *cs;
int status = 0;
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
- struct device_node *np = spi->master->dev.of_node;
-
- if (np) {
- /*
- * In DT environments, the CS GPIOs have already been
- * initialized from the "cs-gpios" property of the node.
- */
- cs = spi_gpio->cs_gpios[spi->chip_select];
- } else {
- /*
- * ... otherwise, take it from spi->controller_data
- */
- cs = (uintptr_t) spi->controller_data;
- }
- if (!spi->controller_state) {
- if (cs != SPI_GPIO_NO_CHIPSELECT) {
- status = gpio_request(cs, dev_name(&spi->dev));
- if (status)
- return status;
- status = gpio_direction_output(cs,
- !(spi->mode & SPI_CS_HIGH));
- }
- }
- if (!status) {
- /* in case it was initialized from static board data */
- spi_gpio->cs_gpios[spi->chip_select] = cs;
+ /*
+ * The CS GPIOs have already been
+ * initialized from the descriptor lookup.
+ */
+ cs = spi_gpio->cs_gpios[spi->chip_select];
+ if (!spi->controller_state && cs)
+ status = gpiod_direction_output(cs,
+ !(spi->mode & SPI_CS_HIGH));
+
+ if (!status)
status = spi_bitbang_setup(spi);
- }
- if (status) {
- if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT)
- gpio_free(cs);
- }
return status;
}
static void spi_gpio_cleanup(struct spi_device *spi)
{
- struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
- unsigned long cs = spi_gpio->cs_gpios[spi->chip_select];
-
- if (cs != SPI_GPIO_NO_CHIPSELECT)
- gpio_free(cs);
spi_bitbang_cleanup(spi);
}
-static int spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
-{
- int value;
-
- value = gpio_request(pin, label);
- if (value == 0) {
- if (is_in)
- value = gpio_direction_input(pin);
- else
- value = gpio_direction_output(pin, 0);
- }
- return value;
-}
-
-static int spi_gpio_request(struct spi_gpio_platform_data *pdata,
- const char *label, u16 *res_flags)
+/*
+ * It can be convenient to use this driver with pins that have alternate
+ * functions associated with a "native" SPI controller if a driver for that
+ * controller is not available, or is missing important functionality.
+ *
+ * On platforms which can do so, configure MISO with a weak pullup unless
+ * there's an external pullup on that signal. That saves power by avoiding
+ * floating signals. (A weak pulldown would save power too, but many
+ * drivers expect to see all-ones data as the no slave "response".)
+ */
+static int spi_gpio_request(struct device *dev,
+ struct spi_gpio *spi_gpio,
+ unsigned int num_chipselects,
+ u16 *mflags)
{
- int value;
-
- /* NOTE: SPI_*_GPIO symbols may reference "pdata" */
+ int i;
- if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI) {
- value = spi_gpio_alloc(SPI_MOSI_GPIO, label, false);
- if (value)
- goto done;
- } else {
+ spi_gpio->mosi = devm_gpiod_get_optional(dev, "mosi", GPIOD_OUT_LOW);
+ if (IS_ERR(spi_gpio->mosi))
+ return PTR_ERR(spi_gpio->mosi);
+ if (!spi_gpio->mosi)
/* HW configuration without MOSI pin */
- *res_flags |= SPI_MASTER_NO_TX;
- }
+ *mflags |= SPI_MASTER_NO_TX;
- if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) {
- value = spi_gpio_alloc(SPI_MISO_GPIO, label, true);
- if (value)
- goto free_mosi;
- } else {
+ spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN);
+ if (IS_ERR(spi_gpio->miso))
+ return PTR_ERR(spi_gpio->miso);
+ if (!spi_gpio->miso)
/* HW configuration without MISO pin */
- *res_flags |= SPI_MASTER_NO_RX;
- }
+ *mflags |= SPI_MASTER_NO_RX;
- value = spi_gpio_alloc(SPI_SCK_GPIO, label, false);
- if (value)
- goto free_miso;
+ spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
+ if (IS_ERR(spi_gpio->mosi))
+ return PTR_ERR(spi_gpio->mosi);
- goto done;
+ for (i = 0; i < num_chipselects; i++) {
+ spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs",
+ i, GPIOD_OUT_HIGH);
+ if (IS_ERR(spi_gpio->cs_gpios[i]))
+ return PTR_ERR(spi_gpio->cs_gpios[i]);
+ }
-free_miso:
- if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
- gpio_free(SPI_MISO_GPIO);
-free_mosi:
- if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
- gpio_free(SPI_MOSI_GPIO);
-done:
- return value;
+ return 0;
}
#ifdef CONFIG_OF
if (!pdata)
return -ENOMEM;
- ret = of_get_named_gpio(np, "gpio-sck", 0);
- if (ret < 0) {
- dev_err(&pdev->dev, "gpio-sck property not found\n");
- goto error_free;
- }
- pdata->sck = ret;
-
- ret = of_get_named_gpio(np, "gpio-miso", 0);
- if (ret < 0) {
- dev_info(&pdev->dev, "gpio-miso property not found, switching to no-rx mode\n");
- pdata->miso = SPI_GPIO_NO_MISO;
- } else
- pdata->miso = ret;
-
- ret = of_get_named_gpio(np, "gpio-mosi", 0);
- if (ret < 0) {
- dev_info(&pdev->dev, "gpio-mosi property not found, switching to no-tx mode\n");
- pdata->mosi = SPI_GPIO_NO_MOSI;
- } else
- pdata->mosi = ret;
ret = of_property_read_u32(np, "num-chipselects", &tmp);
if (ret < 0) {
struct spi_gpio_platform_data *pdata;
u16 master_flags = 0;
bool use_of = 0;
- int num_devices;
status = spi_gpio_probe_dt(pdev);
if (status < 0)
return -ENODEV;
#endif
- if (use_of && !SPI_N_CHIPSEL)
- num_devices = 1;
- else
- num_devices = SPI_N_CHIPSEL;
-
- status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);
- if (status < 0)
- return status;
+ master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio));
+ if (!master)
+ return -ENOMEM;
- master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) +
- (sizeof(unsigned long) * num_devices));
- if (!master) {
- status = -ENOMEM;
- goto gpio_free;
- }
spi_gpio = spi_master_get_devdata(master);
+
+ spi_gpio->cs_gpios = devm_kzalloc(&pdev->dev,
+ pdata->num_chipselect * sizeof(*spi_gpio->cs_gpios),
+ GFP_KERNEL);
+ if (!spi_gpio->cs_gpios)
+ return -ENOMEM;
+
platform_set_drvdata(pdev, spi_gpio);
+ /* Determine if we have chip selects connected */
+ spi_gpio->has_cs = !!pdata->num_chipselect;
+
spi_gpio->pdev = pdev;
if (pdata)
spi_gpio->pdata = *pdata;
+ status = spi_gpio_request(&pdev->dev, spi_gpio,
+ pdata->num_chipselect, &master_flags);
+ if (status)
+ return status;
+
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
master->flags = master_flags;
master->bus_num = pdev->id;
- master->num_chipselect = num_devices;
+ /* The master needs to think there is a chipselect even if not connected */
+ master->num_chipselect = spi_gpio->has_cs ? pdata->num_chipselect : 1;
master->setup = spi_gpio_setup;
master->cleanup = spi_gpio_cleanup;
#ifdef CONFIG_OF
master->dev.of_node = pdev->dev.of_node;
-
- if (use_of) {
- int i;
- struct device_node *np = pdev->dev.of_node;
-
- /*
- * In DT environments, take the CS GPIO from the "cs-gpios"
- * property of the node.
- */
-
- if (!SPI_N_CHIPSEL)
- spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT;
- else
- for (i = 0; i < SPI_N_CHIPSEL; i++) {
- status = of_get_named_gpio(np, "cs-gpios", i);
- if (status < 0) {
- dev_err(&pdev->dev,
- "invalid cs-gpios property\n");
- goto gpio_free;
- }
- spi_gpio->cs_gpios[i] = status;
- }
- }
#endif
spi_gpio->bitbang.master = master;
spi_gpio->bitbang.flags = SPI_CS_HIGH;
status = spi_bitbang_start(&spi_gpio->bitbang);
- if (status < 0) {
-gpio_free:
- if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
- gpio_free(SPI_MISO_GPIO);
- if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
- gpio_free(SPI_MOSI_GPIO);
- gpio_free(SPI_SCK_GPIO);
+ if (status)
spi_master_put(master);
- }
return status;
}
/* stop() unregisters child devices too */
spi_bitbang_stop(&spi_gpio->bitbang);
- if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
- gpio_free(SPI_MISO_GPIO);
- if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
- gpio_free(SPI_MOSI_GPIO);
- gpio_free(SPI_SCK_GPIO);
spi_master_put(spi_gpio->bitbang.master);
return 0;
*/
clock_freq = 50000000;
clk = devm_clk_get(&pdev->dev, "ref_clk");
- if (!IS_ERR_OR_NULL(clk)) {
- if (clk_enable(clk) == 0)
+ if (!IS_ERR(clk)) {
+ if (clk_prepare_enable(clk) == 0) {
clock_freq = clk_get_rate(clk);
- else
+ clk_disable_unprepare(clk);
+ } else
dev_warn(&pdev->dev, "could not enable ref_clk\n");
}
hw->clock_freq = clock_freq;
/* Register our spi controller */
err = devm_spi_register_master(&pdev->dev, master);
- if (err) {
- clk_disable(clk);
+ if (err)
goto exit;
- }
return 0;
u32 size;
};
+struct orion_child_options {
+ struct orion_direct_acc direct_access;
+};
+
struct orion_spi {
struct spi_master *master;
void __iomem *base;
struct clk *clk;
struct clk *axi_clk;
const struct orion_spi_dev *devdata;
+ int unused_hw_gpio;
- struct orion_direct_acc direct_access[ORION_NUM_CHIPSELECTS];
+ struct orion_child_options child[ORION_NUM_CHIPSELECTS];
};
static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
struct orion_spi *orion_spi;
int cs;
+ orion_spi = spi_master_get_devdata(spi->master);
+
if (gpio_is_valid(spi->cs_gpio))
- cs = 0;
+ cs = orion_spi->unused_hw_gpio;
else
cs = spi->chip_select;
- orion_spi = spi_master_get_devdata(spi->master);
-
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK);
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG,
ORION_SPI_CS(cs));
* Use SPI direct write mode if base address is available. Otherwise
* fall back to PIO mode for this transfer.
*/
- if ((orion_spi->direct_access[cs].vaddr) && (xfer->tx_buf) &&
+ if ((orion_spi->child[cs].direct_access.vaddr) && (xfer->tx_buf) &&
(word_len == 8)) {
unsigned int cnt = count / 4;
unsigned int rem = count % 4;
* Send the TX-data to the SPI device via the direct
* mapped address window
*/
- iowrite32_rep(orion_spi->direct_access[cs].vaddr,
+ iowrite32_rep(orion_spi->child[cs].direct_access.vaddr,
xfer->tx_buf, cnt);
if (rem) {
u32 *buf = (u32 *)xfer->tx_buf;
- iowrite8_rep(orion_spi->direct_access[cs].vaddr,
+ iowrite8_rep(orion_spi->child[cs].direct_access.vaddr,
&buf[cnt], rem);
}
static int orion_spi_setup(struct spi_device *spi)
{
+ if (gpio_is_valid(spi->cs_gpio)) {
+ gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
+ }
return orion_spi_setup_transfer(spi, NULL);
}
spi = spi_master_get_devdata(master);
spi->master = master;
+ spi->unused_hw_gpio = -1;
of_id = of_match_device(orion_spi_of_match_table, &pdev->dev);
devdata = (of_id) ? of_id->data : &orion_spi_dev_data;
* This needs to get extended for the direct SPI-NOR / SPI-NAND
* support, once this gets implemented.
*/
- spi->direct_access[cs].vaddr = devm_ioremap(&pdev->dev,
+ spi->child[cs].direct_access.vaddr = devm_ioremap(&pdev->dev,
r->start,
PAGE_SIZE);
- if (!spi->direct_access[cs].vaddr) {
+ if (!spi->child[cs].direct_access.vaddr) {
status = -ENOMEM;
goto out_rel_axi_clk;
}
- spi->direct_access[cs].size = PAGE_SIZE;
+ spi->child[cs].direct_access.size = PAGE_SIZE;
dev_info(&pdev->dev, "CS%d configured for direct access\n", cs);
}
if (status < 0)
goto out_rel_pm;
+ if (master->cs_gpios) {
+ int i;
+ for (i = 0; i < master->num_chipselect; ++i) {
+ char *gpio_name;
+
+ if (!gpio_is_valid(master->cs_gpios[i])) {
+ continue;
+ }
+
+ gpio_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "%s-CS%d", dev_name(&pdev->dev), i);
+ if (!gpio_name) {
+ status = -ENOMEM;
+ goto out_rel_master;
+ }
+
+ status = devm_gpio_request(&pdev->dev,
+ master->cs_gpios[i], gpio_name);
+ if (status) {
+ dev_err(&pdev->dev,
+ "Can't request GPIO for CS %d\n",
+ master->cs_gpios[i]);
+ goto out_rel_master;
+ }
+ if (spi->unused_hw_gpio == -1) {
+ dev_info(&pdev->dev,
+ "Selected unused HW CS#%d for any GPIO CSes\n",
+ i);
+ spi->unused_hw_gpio = i;
+ }
+ }
+ }
+
+
return status;
+out_rel_master:
+ spi_unregister_master(master);
out_rel_pm:
pm_runtime_disable(&pdev->dev);
out_rel_axi_clk:
{
struct pxa2xx_spi_master *pdata = drv_data->master_info;
struct device *dev = &drv_data->pdev->dev;
- struct spi_master *master = drv_data->master;
+ struct spi_controller *master = drv_data->master;
dma_cap_mask_t mask;
dma_cap_zero(mask);
void pxa2xx_spi_dma_release(struct driver_data *drv_data)
{
- struct spi_master *master = drv_data->master;
+ struct spi_controller *master = drv_data->master;
if (master->dma_rx) {
dmaengine_terminate_sync(master->dma_rx);
{
struct chip_data *chip =
spi_get_ctldata(drv_data->master->cur_msg->spi);
+ unsigned long timeout;
if (drv_data->ssp_type == CE4100_SSP)
return;
+ /* Wait until SSP becomes idle before deasserting the CS */
+ timeout = jiffies + msecs_to_jiffies(10);
+ while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY &&
+ !time_after(jiffies, timeout))
+ cpu_relax();
+
if (chip->cs_control) {
chip->cs_control(PXA2XX_CS_DEASSERT);
return;
{
struct spi_transfer* last_transfer;
struct spi_message *msg;
- unsigned long timeout;
msg = drv_data->master->cur_msg;
drv_data->cur_transfer = NULL;
if (last_transfer->delay_usecs)
udelay(last_transfer->delay_usecs);
- /* Wait until SSP becomes idle before deasserting the CS */
- timeout = jiffies + msecs_to_jiffies(10);
- while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY &&
- !time_after(jiffies, timeout))
- cpu_relax();
-
/* Drop chip select UNLESS cs_change is true or we are returning
* a message with an error, or next message is for another chip
*/
return clk_div << 8;
}
-static bool pxa2xx_spi_can_dma(struct spi_master *master,
+static bool pxa2xx_spi_can_dma(struct spi_controller *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
static void pump_transfers(unsigned long data)
{
struct driver_data *drv_data = (struct driver_data *)data;
- struct spi_master *master = drv_data->master;
+ struct spi_controller *master = drv_data->master;
struct spi_message *message = master->cur_msg;
struct chip_data *chip = spi_get_ctldata(message->spi);
u32 dma_thresh = chip->dma_threshold;
pxa2xx_spi_write(drv_data, SSCR1, cr1);
}
-static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
+static int pxa2xx_spi_transfer_one_message(struct spi_controller *master,
struct spi_message *msg)
{
- struct driver_data *drv_data = spi_master_get_devdata(master);
+ struct driver_data *drv_data = spi_controller_get_devdata(master);
/* Initial message state*/
msg->state = START_STATE;
return 0;
}
-static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
+static int pxa2xx_spi_unprepare_transfer(struct spi_controller *master)
{
- struct driver_data *drv_data = spi_master_get_devdata(master);
+ struct driver_data *drv_data = spi_controller_get_devdata(master);
/* Disable the SSP now */
pxa2xx_spi_write(drv_data, SSCR0,
static int setup_cs(struct spi_device *spi, struct chip_data *chip,
struct pxa2xx_spi_chip *chip_info)
{
- struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ struct driver_data *drv_data =
+ spi_controller_get_devdata(spi->controller);
struct gpio_desc *gpiod;
int err = 0;
struct pxa2xx_spi_chip *chip_info;
struct chip_data *chip;
const struct lpss_config *config;
- struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ struct driver_data *drv_data =
+ spi_controller_get_devdata(spi->controller);
uint tx_thres, tx_hi_thres, rx_thres;
switch (drv_data->ssp_type) {
static void cleanup(struct spi_device *spi)
{
struct chip_data *chip = spi_get_ctldata(spi);
- struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ struct driver_data *drv_data =
+ spi_controller_get_devdata(spi->controller);
if (!chip)
return;
}
#endif
-static int pxa2xx_spi_fw_translate_cs(struct spi_master *master, unsigned cs)
+static int pxa2xx_spi_fw_translate_cs(struct spi_controller *master,
+ unsigned int cs)
{
- struct driver_data *drv_data = spi_master_get_devdata(master);
+ struct driver_data *drv_data = spi_controller_get_devdata(master);
if (has_acpi_companion(&drv_data->pdev->dev)) {
switch (drv_data->ssp_type) {
{
struct device *dev = &pdev->dev;
struct pxa2xx_spi_master *platform_info;
- struct spi_master *master;
+ struct spi_controller *master;
struct driver_data *drv_data;
struct ssp_device *ssp;
const struct lpss_config *config;
pxa_ssp_free(ssp);
return -ENOMEM;
}
- drv_data = spi_master_get_devdata(master);
+ drv_data = spi_controller_get_devdata(master);
drv_data->master = master;
drv_data->master_info = platform_info;
drv_data->pdev = pdev;
master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
master->fw_translate_cs = pxa2xx_spi_fw_translate_cs;
master->auto_runtime_pm = true;
- master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
+ master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
drv_data->ssp_type = ssp->type;
/* Register with the SPI framework */
platform_set_drvdata(pdev, drv_data);
- status = devm_spi_register_master(&pdev->dev, master);
+ status = devm_spi_register_controller(&pdev->dev, master);
if (status != 0) {
dev_err(&pdev->dev, "problem registering spi master\n");
goto out_error_clock_enabled;
return status;
out_error_clock_enabled:
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(ssp->clk);
pxa2xx_spi_dma_release(drv_data);
free_irq(ssp->irq, drv_data);
out_error_master_alloc:
- spi_master_put(master);
+ spi_controller_put(master);
pxa_ssp_free(ssp);
return status;
}
struct ssp_device *ssp = drv_data->ssp;
int status;
- status = spi_master_suspend(drv_data->master);
+ status = spi_controller_suspend(drv_data->master);
if (status != 0)
return status;
pxa2xx_spi_write(drv_data, SSCR0, 0);
lpss_ssp_setup(drv_data);
/* Start the queue running */
- status = spi_master_resume(drv_data->master);
+ status = spi_controller_resume(drv_data->master);
if (status != 0) {
dev_err(dev, "problem starting queue (%d)\n", status);
return status;
/* SPI framework hookup */
enum pxa_ssp_type ssp_type;
- struct spi_master *master;
+ struct spi_controller *master;
/* PXA hookup */
struct pxa2xx_spi_master *master_info;
/* First prepare and submit the DMA request(s), as this may fail */
if (rx) {
desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx,
- rx->sgl, rx->nents, DMA_FROM_DEVICE,
+ rx->sgl, rx->nents, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx) {
ret = -EAGAIN;
if (tx) {
desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx,
- tx->sgl, tx->nents, DMA_TO_DEVICE,
+ tx->sgl, tx->nents, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) {
ret = -EAGAIN;
if (rx) {
ier_bits |= IER_RDREQE | IER_RDMAE;
desc_rx = dmaengine_prep_slave_single(p->master->dma_rx,
- p->rx_dma_addr, len, DMA_FROM_DEVICE,
+ p->rx_dma_addr, len, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx)
return -EAGAIN;
dma_sync_single_for_device(p->master->dma_tx->device->dev,
p->tx_dma_addr, len, DMA_TO_DEVICE);
desc_tx = dmaengine_prep_slave_single(p->master->dma_tx,
- p->tx_dma_addr, len, DMA_TO_DEVICE,
+ p->tx_dma_addr, len, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) {
ret = -EAGAIN;
* SPDX-License-Identifier: GPL-2.0
*/
+#include <linux/delay.h>
#include <linux/hwspinlock.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <linux/spi/spi.h>
#include <linux/sizes.h>
#define ADI_READ_TIMEOUT 2000
#define REG_ADDR_LOW_MASK GENMASK(11, 0)
+/* Registers definitions for PMIC watchdog controller */
+#define REG_WDG_LOAD_LOW 0x80
+#define REG_WDG_LOAD_HIGH 0x84
+#define REG_WDG_CTRL 0x88
+#define REG_WDG_LOCK 0xa0
+
+/* Bits definitions for register REG_WDG_CTRL */
+#define BIT_WDG_RUN BIT(1)
+#define BIT_WDG_RST BIT(3)
+
+/* Registers definitions for PMIC */
+#define PMIC_RST_STATUS 0xee8
+#define PMIC_MODULE_EN 0xc08
+#define PMIC_CLK_EN 0xc18
+#define BIT_WDG_EN BIT(2)
+
+/* Definition of PMIC reset status register */
+#define HWRST_STATUS_RECOVERY 0x20
+#define HWRST_STATUS_NORMAL 0x40
+#define HWRST_STATUS_ALARM 0x50
+#define HWRST_STATUS_SLEEP 0x60
+#define HWRST_STATUS_FASTBOOT 0x30
+#define HWRST_STATUS_SPECIAL 0x70
+#define HWRST_STATUS_PANIC 0x80
+#define HWRST_STATUS_CFTREBOOT 0x90
+#define HWRST_STATUS_AUTODLOADER 0xa0
+#define HWRST_STATUS_IQMODE 0xb0
+#define HWRST_STATUS_SPRDISK 0xc0
+
+/* Use default timeout 50 ms that converts to watchdog values */
+#define WDG_LOAD_VAL ((50 * 1000) / 32768)
+#define WDG_LOAD_MASK GENMASK(15, 0)
+#define WDG_UNLOCK_KEY 0xe551
+
struct sprd_adi {
struct spi_controller *ctlr;
struct device *dev;
struct hwspinlock *hwlock;
unsigned long slave_vbase;
unsigned long slave_pbase;
+ struct notifier_block restart_handler;
};
static int sprd_adi_check_paddr(struct sprd_adi *sadi, u32 paddr)
static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val)
{
int read_timeout = ADI_READ_TIMEOUT;
+ unsigned long flags;
u32 val, rd_addr;
+ int ret;
+
+ ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
+ ADI_HWSPINLOCK_TIMEOUT,
+ &flags);
+ if (ret) {
+ dev_err(sadi->dev, "get the hw lock failed\n");
+ return ret;
+ }
/*
* Set the physical register address need to read into RD_CMD register,
if (read_timeout == 0) {
dev_err(sadi->dev, "ADI read timeout\n");
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}
/*
if (rd_addr != (reg_paddr & REG_ADDR_LOW_MASK)) {
dev_err(sadi->dev, "read error, reg addr = 0x%x, val = 0x%x\n",
reg_paddr, val);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
*read_val = val & RD_VALUE_MASK;
- return 0;
+
+out:
+ hwspin_unlock_irqrestore(sadi->hwlock, &flags);
+ return ret;
}
-static int sprd_adi_write(struct sprd_adi *sadi, unsigned long reg, u32 val)
+static int sprd_adi_write(struct sprd_adi *sadi, u32 reg_paddr, u32 val)
{
+ unsigned long reg = sprd_adi_to_vaddr(sadi, reg_paddr);
u32 timeout = ADI_FIFO_DRAIN_TIMEOUT;
+ unsigned long flags;
int ret;
+ ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
+ ADI_HWSPINLOCK_TIMEOUT,
+ &flags);
+ if (ret) {
+ dev_err(sadi->dev, "get the hw lock failed\n");
+ return ret;
+ }
+
ret = sprd_adi_drain_fifo(sadi);
if (ret < 0)
- return ret;
+ goto out;
/*
* we should wait for write fifo is empty before writing data to PMIC
if (timeout == 0) {
dev_err(sadi->dev, "write fifo is full\n");
- return -EBUSY;
+ ret = -EBUSY;
}
- return 0;
+out:
+ hwspin_unlock_irqrestore(sadi->hwlock, &flags);
+ return ret;
}
static int sprd_adi_transfer_one(struct spi_controller *ctlr,
struct spi_transfer *t)
{
struct sprd_adi *sadi = spi_controller_get_devdata(ctlr);
- unsigned long flags, virt_reg;
u32 phy_reg, val;
int ret;
if (ret)
return ret;
- ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
- ADI_HWSPINLOCK_TIMEOUT,
- &flags);
- if (ret) {
- dev_err(sadi->dev, "get the hw lock failed\n");
- return ret;
- }
-
ret = sprd_adi_read(sadi, phy_reg, &val);
- hwspin_unlock_irqrestore(sadi->hwlock, &flags);
if (ret)
return ret;
if (ret)
return ret;
- virt_reg = sprd_adi_to_vaddr(sadi, phy_reg);
val = *p;
-
- ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
- ADI_HWSPINLOCK_TIMEOUT,
- &flags);
- if (ret) {
- dev_err(sadi->dev, "get the hw lock failed\n");
- return ret;
- }
-
- ret = sprd_adi_write(sadi, virt_reg, val);
- hwspin_unlock_irqrestore(sadi->hwlock, &flags);
+ ret = sprd_adi_write(sadi, phy_reg, val);
if (ret)
return ret;
} else {
return 0;
}
+static int sprd_adi_restart_handler(struct notifier_block *this,
+ unsigned long mode, void *cmd)
+{
+ struct sprd_adi *sadi = container_of(this, struct sprd_adi,
+ restart_handler);
+ u32 val, reboot_mode = 0;
+
+ if (!cmd)
+ reboot_mode = HWRST_STATUS_NORMAL;
+ else if (!strncmp(cmd, "recovery", 8))
+ reboot_mode = HWRST_STATUS_RECOVERY;
+ else if (!strncmp(cmd, "alarm", 5))
+ reboot_mode = HWRST_STATUS_ALARM;
+ else if (!strncmp(cmd, "fastsleep", 9))
+ reboot_mode = HWRST_STATUS_SLEEP;
+ else if (!strncmp(cmd, "bootloader", 10))
+ reboot_mode = HWRST_STATUS_FASTBOOT;
+ else if (!strncmp(cmd, "panic", 5))
+ reboot_mode = HWRST_STATUS_PANIC;
+ else if (!strncmp(cmd, "special", 7))
+ reboot_mode = HWRST_STATUS_SPECIAL;
+ else if (!strncmp(cmd, "cftreboot", 9))
+ reboot_mode = HWRST_STATUS_CFTREBOOT;
+ else if (!strncmp(cmd, "autodloader", 11))
+ reboot_mode = HWRST_STATUS_AUTODLOADER;
+ else if (!strncmp(cmd, "iqmode", 6))
+ reboot_mode = HWRST_STATUS_IQMODE;
+ else if (!strncmp(cmd, "sprdisk", 7))
+ reboot_mode = HWRST_STATUS_SPRDISK;
+ else
+ reboot_mode = HWRST_STATUS_NORMAL;
+
+ /* Record the reboot mode */
+ sprd_adi_read(sadi, sadi->slave_pbase + PMIC_RST_STATUS, &val);
+ val |= reboot_mode;
+ sprd_adi_write(sadi, sadi->slave_pbase + PMIC_RST_STATUS, val);
+
+ /* Enable the interface clock of the watchdog */
+ sprd_adi_read(sadi, sadi->slave_pbase + PMIC_MODULE_EN, &val);
+ val |= BIT_WDG_EN;
+ sprd_adi_write(sadi, sadi->slave_pbase + PMIC_MODULE_EN, val);
+
+ /* Enable the work clock of the watchdog */
+ sprd_adi_read(sadi, sadi->slave_pbase + PMIC_CLK_EN, &val);
+ val |= BIT_WDG_EN;
+ sprd_adi_write(sadi, sadi->slave_pbase + PMIC_CLK_EN, val);
+
+ /* Unlock the watchdog */
+ sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, WDG_UNLOCK_KEY);
+
+ /* Load the watchdog timeout value, 50ms is always enough. */
+ sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_LOW,
+ WDG_LOAD_VAL & WDG_LOAD_MASK);
+ sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_HIGH, 0);
+
+ /* Start the watchdog to reset system */
+ sprd_adi_read(sadi, sadi->slave_pbase + REG_WDG_CTRL, &val);
+ val |= BIT_WDG_RUN | BIT_WDG_RST;
+ sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val);
+
+ mdelay(1000);
+
+ dev_emerg(sadi->dev, "Unable to restart system\n");
+ return NOTIFY_DONE;
+}
+
static void sprd_adi_hw_init(struct sprd_adi *sadi)
{
struct device_node *np = sadi->dev->of_node;
goto free_hwlock;
}
+ sadi->restart_handler.notifier_call = sprd_adi_restart_handler;
+ sadi->restart_handler.priority = 128;
+ ret = register_restart_handler(&sadi->restart_handler);
+ if (ret) {
+ dev_err(&pdev->dev, "can not register restart handler\n");
+ goto free_hwlock;
+ }
+
return 0;
free_hwlock:
struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);
struct sprd_adi *sadi = spi_controller_get_devdata(ctlr);
+ unregister_restart_handler(&sadi->restart_handler);
hwspin_lock_free(sadi->hwlock);
return 0;
}
tspi->bytes_per_word = DIV_ROUND_UP(bits_per_word, 8);
if (bits_per_word == 8 || bits_per_word == 16) {
- tspi->is_packed = 1;
+ tspi->is_packed = true;
tspi->words_per_32bit = 32/bits_per_word;
} else {
- tspi->is_packed = 0;
+ tspi->is_packed = false;
tspi->words_per_32bit = 1;
}
tspi->packed_size = tegra_slink_get_packed_size(tspi, t);
for (i = 0; i < sgs; i++) {
if (vmalloced_buf || kmap_buf) {
- min = min_t(size_t,
- len, desc_len - offset_in_page(buf));
+ /*
+ * Next scatterlist entry size is the minimum between
+ * the desc_len and the remaining buffer length that
+ * fits in a page.
+ */
+ min = min_t(size_t, desc_len,
+ min_t(size_t, len,
+ PAGE_SIZE - offset_in_page(buf)));
if (vmalloced_buf)
vm_page = vmalloc_to_page(buf);
else
mutex_lock(&board_lock);
found = idr_find(&spi_master_idr, id);
mutex_unlock(&board_lock);
- if (found != ctlr) {
- dev_dbg(&ctlr->dev,
- "attempting to delete unregistered controller [%s]\n",
- dev_name(&ctlr->dev));
- return;
- }
if (ctlr->queued) {
if (spi_destroy_queue(ctlr))
dev_err(&ctlr->dev, "queue remove failed\n");
device_unregister(&ctlr->dev);
/* free bus id */
mutex_lock(&board_lock);
- idr_remove(&spi_master_idr, id);
+ if (found == ctlr)
+ idr_remove(&spi_master_idr, id);
mutex_unlock(&board_lock);
}
EXPORT_SYMBOL_GPL(spi_unregister_controller);
* - id the same as the SPI bus number it implements
* - dev.platform data pointing to a struct spi_gpio_platform_data
*
- * Or, see the driver code for information about speedups that are
- * possible on platforms that support inlined access for GPIOs (no
- * spi_gpio_platform_data is used).
- *
- * Use spi_board_info with these busses in the usual way, being sure
- * that the controller_data being the GPIO used for each device's
- * chipselect:
- *
- * static struct spi_board_info ... [] = {
- * ...
- * // this slave uses GPIO 42 for its chipselect
- * .controller_data = (void *) 42,
- * ...
- * // this one uses GPIO 86 for its chipselect
- * .controller_data = (void *) 86,
- * ...
- * };
- *
- * If chipselect is not used (there's only one device on the bus), assign
- * SPI_GPIO_NO_CHIPSELECT to the controller_data:
- * .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT;
- *
- * If the MISO or MOSI pin is not available then it should be set to
- * SPI_GPIO_NO_MISO or SPI_GPIO_NO_MOSI.
+ * Use spi_board_info with these busses in the usual way.
*
* If the bitbanged bus is later switched to a "native" controller,
* that platform_device and controller_data should be removed.
*/
-#define SPI_GPIO_NO_CHIPSELECT ((unsigned long)-1l)
-#define SPI_GPIO_NO_MISO ((unsigned long)-1l)
-#define SPI_GPIO_NO_MOSI ((unsigned long)-1l)
-
/**
* struct spi_gpio_platform_data - parameter for bitbanged SPI master
- * @sck: number of the GPIO used for clock output
- * @mosi: number of the GPIO used for Master Output, Slave In (MOSI) data
- * @miso: number of the GPIO used for Master Input, Slave Output (MISO) data
* @num_chipselect: how many slaves to allow
- *
- * All GPIO signals used with the SPI bus managed through this driver
- * (chipselects, MOSI, MISO, SCK) must be configured as GPIOs, instead
- * of some alternate function.
- *
- * It can be convenient to use this driver with pins that have alternate
- * functions associated with a "native" SPI controller if a driver for that
- * controller is not available, or is missing important functionality.
- *
- * On platforms which can do so, configure MISO with a weak pullup unless
- * there's an external pullup on that signal. That saves power by avoiding
- * floating signals. (A weak pulldown would save power too, but many
- * drivers expect to see all-ones data as the no slave "response".)
*/
struct spi_gpio_platform_data {
- unsigned sck;
- unsigned long mosi;
- unsigned long miso;
-
u16 num_chipselect;
};