Commit 92af5c13 authored by Lee Jones's avatar Lee Jones

Merge branches 'ib-mfd-iio-input-4.20', 'ib-mfd-irqchip-4.20',...

Merge branches 'ib-mfd-iio-input-4.20', 'ib-mfd-irqchip-4.20', 'ib-mfd-rtc-4.20' and 'ib-mfd-spi-tty-4.20-1' into ibs-for-mfd-merged
* Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART) * Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART)
Required properties: Required properties for USART:
- compatible: Should be "atmel,<chip>-usart" or "atmel,<chip>-dbgu" - compatible: Should be "atmel,<chip>-usart" or "atmel,<chip>-dbgu"
The compatible <chip> indicated will be the first SoC to support an The compatible <chip> indicated will be the first SoC to support an
additional mode or an USART new feature. additional mode or an USART new feature.
...@@ -11,7 +11,13 @@ Required properties: ...@@ -11,7 +11,13 @@ Required properties:
Required elements: "usart" Required elements: "usart"
- clocks: phandles to input clocks. - clocks: phandles to input clocks.
Optional properties: Required properties for USART in SPI mode:
- #size-cells : Must be <0>
- #address-cells : Must be <1>
- cs-gpios: chipselects (internal cs not supported)
- atmel,usart-mode : Must be <AT91_USART_MODE_SPI> (found in dt-bindings/mfd/at91-usart.h)
Optional properties in serial mode:
- atmel,use-dma-rx: use of PDC or DMA for receiving data - atmel,use-dma-rx: use of PDC or DMA for receiving data
- atmel,use-dma-tx: use of PDC or DMA for transmitting data - atmel,use-dma-tx: use of PDC or DMA for transmitting data
- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD line respectively. - {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD line respectively.
...@@ -62,3 +68,18 @@ Example: ...@@ -62,3 +68,18 @@ Example:
dma-names = "tx", "rx"; dma-names = "tx", "rx";
atmel,fifo-size = <32>; atmel,fifo-size = <32>;
}; };
- SPI mode:
#include <dt-bindings/mfd/at91-usart.h>
spi0: spi@f001c000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "atmel,at91rm9200-usart", "atmel,at91sam9260-usart";
atmel,usart-mode = <AT91_USART_MODE_SPI>;
reg = <0xf001c000 0x100>;
interrupts = <12 IRQ_TYPE_LEVEL_HIGH 5>;
clocks = <&usart0_clk>;
clock-names = "usart";
cs-gpios = <&pioB 3 0>;
};
...@@ -9502,6 +9502,7 @@ M: Richard Genoud <richard.genoud@gmail.com> ...@@ -9502,6 +9502,7 @@ M: Richard Genoud <richard.genoud@gmail.com>
S: Maintained S: Maintained
F: drivers/tty/serial/atmel_serial.c F: drivers/tty/serial/atmel_serial.c
F: drivers/tty/serial/atmel_serial.h F: drivers/tty/serial/atmel_serial.h
F: Documentation/devicetree/bindings/mfd/atmel-usart.txt
MICROCHIP / ATMEL DMA DRIVER MICROCHIP / ATMEL DMA DRIVER
M: Ludovic Desroches <ludovic.desroches@microchip.com> M: Ludovic Desroches <ludovic.desroches@microchip.com>
...@@ -9533,6 +9534,21 @@ S: Supported ...@@ -9533,6 +9534,21 @@ S: Supported
F: drivers/mtd/nand/raw/atmel/* F: drivers/mtd/nand/raw/atmel/*
F: Documentation/devicetree/bindings/mtd/atmel-nand.txt F: Documentation/devicetree/bindings/mtd/atmel-nand.txt
MICROCHIP AT91 USART MFD DRIVER
M: Radu Pirea <radu_nicolae.pirea@upb.ro>
L: linux-kernel@vger.kernel.org
S: Supported
F: drivers/mfd/at91-usart.c
F: include/dt-bindings/mfd/at91-usart.h
F: Documentation/devicetree/bindings/mfd/atmel-usart.txt
MICROCHIP AT91 USART SPI DRIVER
M: Radu Pirea <radu_nicolae.pirea@upb.ro>
L: linux-spi@vger.kernel.org
S: Supported
F: drivers/spi/spi-at91-usart.c
F: Documentation/devicetree/bindings/mfd/atmel-usart.txt
MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER
M: Woojung Huh <Woojung.Huh@microchip.com> M: Woojung Huh <Woojung.Huh@microchip.com>
M: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com> M: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
......
...@@ -99,6 +99,15 @@ config MFD_AAT2870_CORE ...@@ -99,6 +99,15 @@ config MFD_AAT2870_CORE
additional drivers must be enabled in order to use the additional drivers must be enabled in order to use the
functionality of the device. functionality of the device.
config MFD_AT91_USART
tristate "AT91 USART Driver"
select MFD_CORE
help
Select this to get support for AT91 USART IP. This is a wrapper
over at91-usart-serial driver and usart-spi-driver. Only one function
can be used at a time. The choice is done at boot time by the probe
function of this MFD driver according to a device tree property.
config MFD_ATMEL_FLEXCOM config MFD_ATMEL_FLEXCOM
tristate "Atmel Flexcom (Flexible Serial Communication Unit)" tristate "Atmel Flexcom (Flexible Serial Communication Unit)"
select MFD_CORE select MFD_CORE
......
...@@ -196,6 +196,7 @@ obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o ...@@ -196,6 +196,7 @@ obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_AT91_USART) += at91-usart.o
obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o
obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o
obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for AT91 USART
*
* Copyright (C) 2018 Microchip Technology
*
* Author: Radu Pirea <radu.pirea@microchip.com>
*
*/
#include <dt-bindings/mfd/at91-usart.h>
#include <linux/module.h>
#include <linux/mfd/core.h>
#include <linux/of.h>
#include <linux/property.h>
static struct mfd_cell at91_usart_spi_subdev = {
.name = "at91_usart_spi",
.of_compatible = "microchip,at91sam9g45-usart-spi",
};
static struct mfd_cell at91_usart_serial_subdev = {
.name = "atmel_usart_serial",
.of_compatible = "atmel,at91rm9200-usart-serial",
};
static int at91_usart_mode_probe(struct platform_device *pdev)
{
struct mfd_cell cell;
u32 opmode = AT91_USART_MODE_SERIAL;
device_property_read_u32(&pdev->dev, "atmel,usart-mode", &opmode);
switch (opmode) {
case AT91_USART_MODE_SPI:
cell = at91_usart_spi_subdev;
break;
case AT91_USART_MODE_SERIAL:
cell = at91_usart_serial_subdev;
break;
default:
dev_err(&pdev->dev, "atmel,usart-mode has an invalid value %u\n",
opmode);
return -EINVAL;
}
return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO, &cell, 1,
NULL, 0, NULL);
}
static const struct of_device_id at91_usart_mode_of_match[] = {
{ .compatible = "atmel,at91rm9200-usart" },
{ .compatible = "atmel,at91sam9260-usart" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, at91_usart_mode_of_match);
static struct platform_driver at91_usart_mfd = {
.probe = at91_usart_mode_probe,
.driver = {
.name = "at91_usart_mode",
.of_match_table = at91_usart_mode_of_match,
},
};
module_platform_driver(at91_usart_mfd);
MODULE_AUTHOR("Radu Pirea <radu.pirea@microchip.com>");
MODULE_DESCRIPTION("AT91 USART MFD driver");
MODULE_LICENSE("GPL v2");
...@@ -1094,6 +1094,7 @@ static void menelaus_rtc_alarm_work(struct menelaus_chip *m) ...@@ -1094,6 +1094,7 @@ static void menelaus_rtc_alarm_work(struct menelaus_chip *m)
static inline void menelaus_rtc_init(struct menelaus_chip *m) static inline void menelaus_rtc_init(struct menelaus_chip *m)
{ {
int alarm = (m->client->irq > 0); int alarm = (m->client->irq > 0);
int err;
/* assume 32KDETEN pin is pulled high */ /* assume 32KDETEN pin is pulled high */
if (!(menelaus_read_reg(MENELAUS_OSC_CTRL) & 0x80)) { if (!(menelaus_read_reg(MENELAUS_OSC_CTRL) & 0x80)) {
...@@ -1101,6 +1102,12 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m) ...@@ -1101,6 +1102,12 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m)
return; return;
} }
m->rtc = devm_rtc_allocate_device(&m->client->dev);
if (IS_ERR(m->rtc))
return;
m->rtc->ops = &menelaus_rtc_ops;
/* support RTC alarm; it can issue wakeups */ /* support RTC alarm; it can issue wakeups */
if (alarm) { if (alarm) {
if (menelaus_add_irq_work(MENELAUS_RTCALM_IRQ, if (menelaus_add_irq_work(MENELAUS_RTCALM_IRQ,
...@@ -1125,10 +1132,8 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m) ...@@ -1125,10 +1132,8 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m)
menelaus_write_reg(MENELAUS_RTC_CTRL, m->rtc_control); menelaus_write_reg(MENELAUS_RTC_CTRL, m->rtc_control);
} }
m->rtc = rtc_device_register(DRIVER_NAME, err = rtc_register_device(m->rtc);
&m->client->dev, if (err) {
&menelaus_rtc_ops, THIS_MODULE);
if (IS_ERR(m->rtc)) {
if (alarm) { if (alarm) {
menelaus_remove_irq_work(MENELAUS_RTCALM_IRQ); menelaus_remove_irq_work(MENELAUS_RTCALM_IRQ);
device_init_wakeup(&m->client->dev, 0); device_init_wakeup(&m->client->dev, 0);
......
...@@ -83,6 +83,14 @@ config SPI_ATMEL ...@@ -83,6 +83,14 @@ config SPI_ATMEL
This selects a driver for the Atmel SPI Controller, present on This selects a driver for the Atmel SPI Controller, present on
many AT91 ARM chips. many AT91 ARM chips.
config SPI_AT91_USART
tristate "Atmel USART Controller SPI driver"
depends on (ARCH_AT91 || COMPILE_TEST)
depends on MFD_AT91_USART
help
This selects a driver for the AT91 USART Controller as SPI Master,
present on AT91 and SAMA5 SoC series.
config SPI_AU1550 config SPI_AU1550
tristate "Au1550/Au1200/Au1300 SPI Controller" tristate "Au1550/Au1200/Au1300 SPI Controller"
depends on MIPS_ALCHEMY depends on MIPS_ALCHEMY
......
...@@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o ...@@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o
obj-$(CONFIG_SPI_ALTERA) += spi-altera.o obj-$(CONFIG_SPI_ALTERA) += spi-altera.o
obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o
obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_AT91_USART) += spi-at91-usart.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
obj-$(CONFIG_SPI_AXI_SPI_ENGINE) += spi-axi-spi-engine.o obj-$(CONFIG_SPI_AXI_SPI_ENGINE) += spi-axi-spi-engine.o
......
// SPDX-License-Identifier: GPL-2.0
//
// Driver for AT91 USART Controllers as SPI
//
// Copyright (C) 2018 Microchip Technology Inc.
//
// Author: Radu Pirea <radu.pirea@microchip.com>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#define US_CR 0x00
#define US_MR 0x04
#define US_IER 0x08
#define US_IDR 0x0C
#define US_CSR 0x14
#define US_RHR 0x18
#define US_THR 0x1C
#define US_BRGR 0x20
#define US_VERSION 0xFC
#define US_CR_RSTRX BIT(2)
#define US_CR_RSTTX BIT(3)
#define US_CR_RXEN BIT(4)
#define US_CR_RXDIS BIT(5)
#define US_CR_TXEN BIT(6)
#define US_CR_TXDIS BIT(7)
#define US_MR_SPI_MASTER 0x0E
#define US_MR_CHRL GENMASK(7, 6)
#define US_MR_CPHA BIT(8)
#define US_MR_CPOL BIT(16)
#define US_MR_CLKO BIT(18)
#define US_MR_WRDBT BIT(20)
#define US_MR_LOOP BIT(15)
#define US_IR_RXRDY BIT(0)
#define US_IR_TXRDY BIT(1)
#define US_IR_OVRE BIT(5)
#define US_BRGR_SIZE BIT(16)
#define US_MIN_CLK_DIV 0x06
#define US_MAX_CLK_DIV BIT(16)
#define US_RESET (US_CR_RSTRX | US_CR_RSTTX)
#define US_DISABLE (US_CR_RXDIS | US_CR_TXDIS)
#define US_ENABLE (US_CR_RXEN | US_CR_TXEN)
#define US_OVRE_RXRDY_IRQS (US_IR_OVRE | US_IR_RXRDY)
#define US_INIT \
(US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT)
/* Register access macros */
#define at91_usart_spi_readl(port, reg) \
readl_relaxed((port)->regs + US_##reg)
#define at91_usart_spi_writel(port, reg, value) \
writel_relaxed((value), (port)->regs + US_##reg)
#define at91_usart_spi_readb(port, reg) \
readb_relaxed((port)->regs + US_##reg)
#define at91_usart_spi_writeb(port, reg, value) \
writeb_relaxed((value), (port)->regs + US_##reg)
struct at91_usart_spi {
struct spi_transfer *current_transfer;
void __iomem *regs;
struct device *dev;
struct clk *clk;
/*used in interrupt to protect data reading*/
spinlock_t lock;
int irq;
unsigned int current_tx_remaining_bytes;
unsigned int current_rx_remaining_bytes;
u32 spi_clk;
u32 status;
bool xfer_failed;
};
static inline u32 at91_usart_spi_tx_ready(struct at91_usart_spi *aus)
{
return aus->status & US_IR_TXRDY;
}
static inline u32 at91_usart_spi_rx_ready(struct at91_usart_spi *aus)
{
return aus->status & US_IR_RXRDY;
}
static inline u32 at91_usart_spi_check_overrun(struct at91_usart_spi *aus)
{
return aus->status & US_IR_OVRE;
}
static inline u32 at91_usart_spi_read_status(struct at91_usart_spi *aus)
{
aus->status = at91_usart_spi_readl(aus, CSR);
return aus->status;
}
static inline void at91_usart_spi_tx(struct at91_usart_spi *aus)
{
unsigned int len = aus->current_transfer->len;
unsigned int remaining = aus->current_tx_remaining_bytes;
const u8 *tx_buf = aus->current_transfer->tx_buf;
if (!remaining)
return;
if (at91_usart_spi_tx_ready(aus)) {
at91_usart_spi_writeb(aus, THR, tx_buf[len - remaining]);
aus->current_tx_remaining_bytes--;
}
}
static inline void at91_usart_spi_rx(struct at91_usart_spi *aus)
{
int len = aus->current_transfer->len;
int remaining = aus->current_rx_remaining_bytes;
u8 *rx_buf = aus->current_transfer->rx_buf;
if (!remaining)
return;
rx_buf[len - remaining] = at91_usart_spi_readb(aus, RHR);
aus->current_rx_remaining_bytes--;
}
static inline void
at91_usart_spi_set_xfer_speed(struct at91_usart_spi *aus,
struct spi_transfer *xfer)
{
at91_usart_spi_writel(aus, BRGR,
DIV_ROUND_UP(aus->spi_clk, xfer->speed_hz));
}
static irqreturn_t at91_usart_spi_interrupt(int irq, void *dev_id)
{
struct spi_controller *controller = dev_id;
struct at91_usart_spi *aus = spi_master_get_devdata(controller);
spin_lock(&aus->lock);
at91_usart_spi_read_status(aus);
if (at91_usart_spi_check_overrun(aus)) {
aus->xfer_failed = true;
at91_usart_spi_writel(aus, IDR, US_IR_OVRE | US_IR_RXRDY);
spin_unlock(&aus->lock);
return IRQ_HANDLED;
}
if (at91_usart_spi_rx_ready(aus)) {
at91_usart_spi_rx(aus);
spin_unlock(&aus->lock);
return IRQ_HANDLED;
}
spin_unlock(&aus->lock);
return IRQ_NONE;
}
static int at91_usart_spi_setup(struct spi_device *spi)
{
struct at91_usart_spi *aus = spi_master_get_devdata(spi->controller);
u32 *ausd = spi->controller_state;
unsigned int mr = at91_usart_spi_readl(aus, MR);
u8 bits = spi->bits_per_word;
if (bits != 8) {
dev_dbg(&spi->dev, "Only 8 bits per word are supported\n");
return -EINVAL;
}
if (spi->mode & SPI_CPOL)
mr |= US_MR_CPOL;
else
mr &= ~US_MR_CPOL;
if (spi->mode & SPI_CPHA)
mr |= US_MR_CPHA;
else
mr &= ~US_MR_CPHA;
if (spi->mode & SPI_LOOP)
mr |= US_MR_LOOP;
else
mr &= ~US_MR_LOOP;
if (!ausd) {
ausd = kzalloc(sizeof(*ausd), GFP_KERNEL);
if (!ausd)
return -ENOMEM;
spi->controller_state = ausd;
}
*ausd = mr;
dev_dbg(&spi->dev,
"setup: bpw %u mode 0x%x -> mr %d %08x\n",
bits, spi->mode, spi->chip_select, mr);
return 0;
}
static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
at91_usart_spi_set_xfer_speed(aus, xfer);
aus->xfer_failed = false;
aus->current_transfer = xfer;
aus->current_tx_remaining_bytes = xfer->len;
aus->current_rx_remaining_bytes = xfer->len;
while ((aus->current_tx_remaining_bytes ||
aus->current_rx_remaining_bytes) && !aus->xfer_failed) {
at91_usart_spi_read_status(aus);
at91_usart_spi_tx(aus);
cpu_relax();
}
if (aus->xfer_failed) {
dev_err(aus->dev, "Overrun!\n");
return -EIO;
}
return 0;
}
static int at91_usart_spi_prepare_message(struct spi_controller *ctlr,
struct spi_message *message)
{
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
struct spi_device *spi = message->spi;
u32 *ausd = spi->controller_state;
at91_usart_spi_writel(aus, CR, US_ENABLE);
at91_usart_spi_writel(aus, IER, US_OVRE_RXRDY_IRQS);
at91_usart_spi_writel(aus, MR, *ausd);
return 0;
}
static int at91_usart_spi_unprepare_message(struct spi_controller *ctlr,
struct spi_message *message)
{
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
at91_usart_spi_writel(aus, CR, US_RESET | US_DISABLE);
at91_usart_spi_writel(aus, IDR, US_OVRE_RXRDY_IRQS);
return 0;
}
static void at91_usart_spi_cleanup(struct spi_device *spi)
{
struct at91_usart_spi_device *ausd = spi->controller_state;
spi->controller_state = NULL;
kfree(ausd);
}
static void at91_usart_spi_init(struct at91_usart_spi *aus)
{
at91_usart_spi_writel(aus, MR, US_INIT);
at91_usart_spi_writel(aus, CR, US_RESET | US_DISABLE);
}
static int at91_usart_gpio_setup(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.parent->of_node;
int i;
int ret;
int nb;
if (!np)
return -EINVAL;
nb = of_gpio_named_count(np, "cs-gpios");
for (i = 0; i < nb; i++) {
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
if (cs_gpio < 0)
return cs_gpio;
if (gpio_is_valid(cs_gpio)) {
ret = devm_gpio_request_one(&pdev->dev, cs_gpio,
GPIOF_DIR_OUT,
dev_name(&pdev->dev));
if (ret)
return ret;
}
}
return 0;
}
static int at91_usart_spi_probe(struct platform_device *pdev)
{
struct resource *regs;
struct spi_controller *controller;
struct at91_usart_spi *aus;
struct clk *clk;
int irq;
int ret;
regs = platform_get_resource(to_platform_device(pdev->dev.parent),
IORESOURCE_MEM, 0);
if (!regs)
return -EINVAL;
irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0);
if (irq < 0)
return irq;
clk = devm_clk_get(pdev->dev.parent, "usart");
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = -ENOMEM;
controller = spi_alloc_master(&pdev->dev, sizeof(*aus));
if (!controller)
goto at91_usart_spi_probe_fail;
ret = at91_usart_gpio_setup(pdev);
if (ret)
goto at91_usart_spi_probe_fail;
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH;
controller->dev.of_node = pdev->dev.parent->of_node;
controller->bits_per_word_mask = SPI_BPW_MASK(8);
controller->setup = at91_usart_spi_setup;
controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
controller->transfer_one = at91_usart_spi_transfer_one;
controller->prepare_message = at91_usart_spi_prepare_message;
controller->unprepare_message = at91_usart_spi_unprepare_message;
controller->cleanup = at91_usart_spi_cleanup;
controller->max_speed_hz = DIV_ROUND_UP(clk_get_rate(clk),
US_MIN_CLK_DIV);
controller->min_speed_hz = DIV_ROUND_UP(clk_get_rate(clk),
US_MAX_CLK_DIV);
platform_set_drvdata(pdev, controller);
aus = spi_master_get_devdata(controller);
aus->dev = &pdev->dev;
aus->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(aus->regs)) {
ret = PTR_ERR(aus->regs);
goto at91_usart_spi_probe_fail;
}
aus->irq = irq;
aus->clk = clk;
ret = devm_request_irq(&pdev->dev, irq, at91_usart_spi_interrupt, 0,
dev_name(&pdev->dev), controller);
if (ret)
goto at91_usart_spi_probe_fail;
ret = clk_prepare_enable(clk);
if (ret)
goto at91_usart_spi_probe_fail;
aus->spi_clk = clk_get_rate(clk);
at91_usart_spi_init(aus);
spin_lock_init(&aus->lock);
ret = devm_spi_register_master(&pdev->dev, controller);
if (ret)
goto at91_usart_fail_register_master;
dev_info(&pdev->dev,
"AT91 USART SPI Controller version 0x%x at %pa (irq %d)\n",
at91_usart_spi_readl(aus, VERSION),
&regs->start, irq);
return 0;
at91_usart_fail_register_master:
clk_disable_unprepare(clk);
at91_usart_spi_probe_fail:
spi_master_put(controller);
return ret;
}
static int at91_usart_spi_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
clk_disable_unprepare(aus->clk);
return 0;
}
static const struct of_device_id at91_usart_spi_dt_ids[] = {
{ .compatible = "microchip,at91sam9g45-usart-spi"},
{ /* sentinel */}
};
MODULE_DEVICE_TABLE(of, at91_usart_spi_dt_ids);
static struct platform_driver at91_usart_spi_driver = {
.driver = {
.name = "at91_usart_spi",
},
.probe = at91_usart_spi_probe,
.remove = at91_usart_spi_remove,
};
module_platform_driver(at91_usart_spi_driver);
MODULE_DESCRIPTION("Microchip AT91 USART SPI Controller driver");
MODULE_AUTHOR("Radu Pirea <radu.pirea@microchip.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:at91_usart_spi");
...@@ -118,6 +118,7 @@ config SERIAL_ATMEL ...@@ -118,6 +118,7 @@ config SERIAL_ATMEL
depends on ARCH_AT91 || COMPILE_TEST depends on ARCH_AT91 || COMPILE_TEST
select SERIAL_CORE select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB select SERIAL_MCTRL_GPIO if GPIOLIB
select MFD_AT91_USART
help help
This enables the driver for the on-chip UARTs of the Atmel This enables the driver for the on-chip UARTs of the Atmel
AT91 processors. AT91 processors.
......
...@@ -193,8 +193,7 @@ static struct console atmel_console; ...@@ -193,8 +193,7 @@ static struct console atmel_console;
#if defined(CONFIG_OF) #if defined(CONFIG_OF)
static const struct of_device_id atmel_serial_dt_ids[] = { static const struct of_device_id atmel_serial_dt_ids[] = {
{ .compatible = "atmel,at91rm9200-usart" }, { .compatible = "atmel,at91rm9200-usart-serial" },
{ .compatible = "atmel,at91sam9260-usart" },
{ /* sentinel */ } { /* sentinel */ }
}; };
#endif #endif
...@@ -915,6 +914,7 @@ static void atmel_tx_dma(struct uart_port *port) ...@@ -915,6 +914,7 @@ static void atmel_tx_dma(struct uart_port *port)
static int atmel_prepare_tx_dma(struct uart_port *port) static int atmel_prepare_tx_dma(struct uart_port *port)
{ {
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
struct device *mfd_dev = port->dev->parent;
dma_cap_mask_t mask; dma_cap_mask_t mask;
struct dma_slave_config config; struct dma_slave_config config;
int ret, nent; int ret, nent;
...@@ -922,7 +922,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) ...@@ -922,7 +922,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
atmel_port->chan_tx = dma_request_slave_channel(port->dev, "tx"); atmel_port->chan_tx = dma_request_slave_channel(mfd_dev, "tx");
if (atmel_port->chan_tx == NULL) if (atmel_port->chan_tx == NULL)
goto chan_err; goto chan_err;
dev_info(port->dev, "using %s for tx DMA transfers\n", dev_info(port->dev, "using %s for tx DMA transfers\n",
...@@ -1093,6 +1093,7 @@ static void atmel_rx_from_dma(struct uart_port *port) ...@@ -1093,6 +1093,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
static int atmel_prepare_rx_dma(struct uart_port *port) static int atmel_prepare_rx_dma(struct uart_port *port)
{ {
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
struct device *mfd_dev = port->dev->parent;
struct dma_async_tx_descriptor *desc; struct dma_async_tx_descriptor *desc;
dma_cap_mask_t mask; dma_cap_mask_t mask;
struct dma_slave_config config; struct dma_slave_config config;
...@@ -1104,7 +1105,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port) ...@@ -1104,7 +1105,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_CYCLIC, mask); dma_cap_set(DMA_CYCLIC, mask);
atmel_port->chan_rx = dma_request_slave_channel(port->dev, "rx"); atmel_port->chan_rx = dma_request_slave_channel(mfd_dev, "rx");
if (atmel_port->chan_rx == NULL) if (atmel_port->chan_rx == NULL)
goto chan_err; goto chan_err;
dev_info(port->dev, "using %s for rx DMA transfers\n", dev_info(port->dev, "using %s for rx DMA transfers\n",
...@@ -2222,8 +2223,8 @@ static const char *atmel_type(struct uart_port *port) ...@@ -2222,8 +2223,8 @@ static const char *atmel_type(struct uart_port *port)
*/ */
static void atmel_release_port(struct uart_port *port) static void atmel_release_port(struct uart_port *port)
{ {
struct platform_device *pdev = to_platform_device(port->dev); struct platform_device *mpdev = to_platform_device(port->dev->parent);
int size = pdev->resource[0].end - pdev->resource[0].start + 1; int size = resource_size(mpdev->resource);
release_mem_region(port->mapbase, size); release_mem_region(port->mapbase, size);
...@@ -2238,8 +2239,8 @@ static void atmel_release_port(struct uart_port *port) ...@@ -2238,8 +2239,8 @@ static void atmel_release_port(struct uart_port *port)
*/ */
static int atmel_request_port(struct uart_port *port) static int atmel_request_port(struct uart_port *port)
{ {
struct platform_device *pdev = to_platform_device(port->dev); struct platform_device *mpdev = to_platform_device(port->dev->parent);
int size = pdev->resource[0].end - pdev->resource[0].start + 1; int size = resource_size(mpdev->resource);
if (!request_mem_region(port->mapbase, size, "atmel_serial")) if (!request_mem_region(port->mapbase, size, "atmel_serial"))
return -EBUSY; return -EBUSY;
...@@ -2341,19 +2342,20 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, ...@@ -2341,19 +2342,20 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
{ {
int ret; int ret;
struct uart_port *port = &atmel_port->uart; struct uart_port *port = &atmel_port->uart;
struct platform_device *mpdev = to_platform_device(pdev->dev.parent);
atmel_init_property(atmel_port, pdev); atmel_init_property(atmel_port, pdev);
atmel_set_ops(port); atmel_set_ops(port);
uart_get_rs485_mode(&pdev->dev, &port->rs485); uart_get_rs485_mode(&mpdev->dev, &port->rs485);
port->iotype = UPIO_MEM; port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
port->ops = &atmel_pops; port->ops = &atmel_pops;
port->fifosize = 1; port->fifosize = 1;
port->dev = &pdev->dev; port->dev = &pdev->dev;
port->mapbase = pdev->resource[0].start; port->mapbase = mpdev->resource[0].start;
port->irq = pdev->resource[1].start; port->irq = mpdev->resource[1].start;
port->rs485_config = atmel_config_rs485; port->rs485_config = atmel_config_rs485;
port->membase = NULL; port->membase = NULL;
...@@ -2361,7 +2363,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, ...@@ -2361,7 +2363,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
/* for console, the clock could already be configured */ /* for console, the clock could already be configured */
if (!atmel_port->clk) { if (!atmel_port->clk) {
atmel_port->clk = clk_get(&pdev->dev, "usart"); atmel_port->clk = clk_get(&mpdev->dev, "usart");
if (IS_ERR(atmel_port->clk)) { if (IS_ERR(atmel_port->clk)) {
ret = PTR_ERR(atmel_port->clk); ret = PTR_ERR(atmel_port->clk);
atmel_port->clk = NULL; atmel_port->clk = NULL;
...@@ -2694,13 +2696,22 @@ static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port, ...@@ -2694,13 +2696,22 @@ static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port,
static int atmel_serial_probe(struct platform_device *pdev) static int atmel_serial_probe(struct platform_device *pdev)
{ {
struct atmel_uart_port *atmel_port; struct atmel_uart_port *atmel_port;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.parent->of_node;
void *data; void *data;
int ret = -ENODEV; int ret = -ENODEV;
bool rs485_enabled; bool rs485_enabled;
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
/*
* In device tree there is no node with "atmel,at91rm9200-usart-serial"
* as compatible string. This driver is probed by at91-usart mfd driver
* which is just a wrapper over the atmel_serial driver and
* spi-at91-usart driver. All attributes needed by this driver are
* found in of_node of parent.
*/
pdev->dev.of_node = np;
ret = of_alias_get_id(np, "serial"); ret = of_alias_get_id(np, "serial");
if (ret < 0) if (ret < 0)
/* port id not found in platform data nor device-tree aliases: /* port id not found in platform data nor device-tree aliases:
...@@ -2836,6 +2847,7 @@ static int atmel_serial_remove(struct platform_device *pdev) ...@@ -2836,6 +2847,7 @@ static int atmel_serial_remove(struct platform_device *pdev)
clk_put(atmel_port->clk); clk_put(atmel_port->clk);
atmel_port->clk = NULL; atmel_port->clk = NULL;
pdev->dev.of_node = NULL;
return ret; return ret;
} }
...@@ -2846,7 +2858,7 @@ static struct platform_driver atmel_serial_driver = { ...@@ -2846,7 +2858,7 @@ static struct platform_driver atmel_serial_driver = {
.suspend = atmel_serial_suspend, .suspend = atmel_serial_suspend,
.resume = atmel_serial_resume, .resume = atmel_serial_resume,
.driver = { .driver = {
.name = "atmel_usart", .name = "atmel_usart_serial",
.of_match_table = of_match_ptr(atmel_serial_dt_ids), .of_match_table = of_match_ptr(atmel_serial_dt_ids),
}, },
}; };
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This header provides macros for AT91 USART DT bindings.
*
* Copyright (C) 2018 Microchip Technology
*
* Author: Radu Pirea <radu.pirea@microchip.com>
*
*/
#ifndef __DT_BINDINGS_AT91_USART_H__
#define __DT_BINDINGS_AT91_USART_H__
#define AT91_USART_MODE_SERIAL 0
#define AT91_USART_MODE_SPI 1
#endif /* __DT_BINDINGS_AT91_USART_H__ */
...@@ -148,6 +148,7 @@ struct snd_soc_dapm_context; ...@@ -148,6 +148,7 @@ struct snd_soc_dapm_context;
* @internal_dcvdd: true if DCVDD is supplied from the internal LDO1 * @internal_dcvdd: true if DCVDD is supplied from the internal LDO1
* @pdata: our pdata * @pdata: our pdata
* @irq_dev: the irqchip child driver device * @irq_dev: the irqchip child driver device
* @irq_data: pointer to irqchip data for the child irqchip driver
* @irq: host irq number from SPI or I2C configuration * @irq: host irq number from SPI or I2C configuration
* @out_clamp: indicates output clamp state for each analogue output * @out_clamp: indicates output clamp state for each analogue output
* @out_shorted: indicates short circuit state for each analogue output * @out_shorted: indicates short circuit state for each analogue output
...@@ -175,6 +176,7 @@ struct madera { ...@@ -175,6 +176,7 @@ struct madera {
struct madera_pdata pdata; struct madera_pdata pdata;
struct device *irq_dev; struct device *irq_dev;
struct regmap_irq_chip_data *irq_data;
int irq; int irq;
unsigned int num_micbias; unsigned int num_micbias;
......
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