u-boot-brain/drivers/serial/serial_owl.c
Simon Glass 41575d8e4c dm: treewide: Rename auto_alloc_size members to be shorter
This construct is quite long-winded. In earlier days it made some sense
since auto-allocation was a strange concept. But with driver model now
used pretty universally, we can shorten this to 'auto'. This reduces
verbosity and makes it easier to read.

Coincidentally it also ensures that every declaration is on one line,
thus making dtoc's job easier.

Signed-off-by: Simon Glass <sjg@chromium.org>
2020-12-13 08:00:25 -07:00

137 lines
3.1 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Actions Semi OWL SoCs UART driver
*
* Copyright (C) 2015 Actions Semi Co., Ltd.
* Copyright (C) 2018 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <serial.h>
#include <asm/io.h>
#include <asm/types.h>
#include <linux/bitops.h>
/* UART Registers */
#define OWL_UART_CTL (0x0000)
#define OWL_UART_RXDAT (0x0004)
#define OWL_UART_TXDAT (0x0008)
#define OWL_UART_STAT (0x000C)
/* UART_CTL Register Definitions */
#define OWL_UART_CTL_PRS_NONE GENMASK(6, 4)
#define OWL_UART_CTL_STPS BIT(2)
#define OWL_UART_CTL_DWLS 3
/* UART_STAT Register Definitions */
#define OWL_UART_STAT_TFES BIT(10) /* TX FIFO Empty Status */
#define OWL_UART_STAT_RFFS BIT(9) /* RX FIFO full Status */
#define OWL_UART_STAT_TFFU BIT(6) /* TX FIFO full Status */
#define OWL_UART_STAT_RFEM BIT(5) /* RX FIFO Empty Status */
struct owl_serial_priv {
phys_addr_t base;
};
int owl_serial_setbrg(struct udevice *dev, int baudrate)
{
/* Driver supports only fixed baudrate */
return 0;
}
static int owl_serial_getc(struct udevice *dev)
{
struct owl_serial_priv *priv = dev_get_priv(dev);
if (readl(priv->base + OWL_UART_STAT) & OWL_UART_STAT_RFEM)
return -EAGAIN;
return (int)(readl(priv->base + OWL_UART_RXDAT));
}
static int owl_serial_putc(struct udevice *dev, const char ch)
{
struct owl_serial_priv *priv = dev_get_priv(dev);
if (readl(priv->base + OWL_UART_STAT) & OWL_UART_STAT_TFFU)
return -EAGAIN;
writel(ch, priv->base + OWL_UART_TXDAT);
return 0;
}
static int owl_serial_pending(struct udevice *dev, bool input)
{
struct owl_serial_priv *priv = dev_get_priv(dev);
unsigned int stat = readl(priv->base + OWL_UART_STAT);
if (input)
return !(stat & OWL_UART_STAT_RFEM);
else
return !(stat & OWL_UART_STAT_TFES);
}
static int owl_serial_probe(struct udevice *dev)
{
struct owl_serial_priv *priv = dev_get_priv(dev);
struct clk clk;
u32 uart_ctl;
int ret;
/* Set data, parity and stop bits */
uart_ctl = readl(priv->base + OWL_UART_CTL);
uart_ctl &= ~(OWL_UART_CTL_PRS_NONE);
uart_ctl &= ~(OWL_UART_CTL_STPS);
uart_ctl |= OWL_UART_CTL_DWLS;
writel(uart_ctl, priv->base + OWL_UART_CTL);
/* Enable UART clock */
ret = clk_get_by_index(dev, 0, &clk);
if (ret < 0)
return ret;
ret = clk_enable(&clk);
if (ret < 0)
return ret;
return 0;
}
static int owl_serial_ofdata_to_platdata(struct udevice *dev)
{
struct owl_serial_priv *priv = dev_get_priv(dev);
priv->base = dev_read_addr(dev);
if (priv->base == FDT_ADDR_T_NONE)
return -EINVAL;
return 0;
}
static const struct dm_serial_ops owl_serial_ops = {
.putc = owl_serial_putc,
.pending = owl_serial_pending,
.getc = owl_serial_getc,
.setbrg = owl_serial_setbrg,
};
static const struct udevice_id owl_serial_ids[] = {
{ .compatible = "actions,owl-uart" },
{ }
};
U_BOOT_DRIVER(serial_owl) = {
.name = "serial_owl",
.id = UCLASS_SERIAL,
.of_match = owl_serial_ids,
.ofdata_to_platdata = owl_serial_ofdata_to_platdata,
.priv_auto = sizeof(struct owl_serial_priv),
.probe = owl_serial_probe,
.ops = &owl_serial_ops,
};