aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/8250/8250_aspeed_vuart.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/8250/8250_aspeed_vuart.c')
-rw-r--r--drivers/tty/serial/8250/8250_aspeed_vuart.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
index 0438d9a905ce..6e67fd89445a 100644
--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
@@ -14,6 +14,8 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/clk.h>
@@ -22,6 +24,7 @@
#define ASPEED_VUART_GCRA 0x20
#define ASPEED_VUART_GCRA_VUART_EN BIT(0)
+#define ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY BIT(1)
#define ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5)
#define ASPEED_VUART_GCRB 0x24
#define ASPEED_VUART_GCRB_HOST_SIRQ_MASK GENMASK(7, 4)
@@ -131,8 +134,53 @@ static ssize_t sirq_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RW(sirq);
+static ssize_t sirq_polarity_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct aspeed_vuart *vuart = dev_get_drvdata(dev);
+ u8 reg;
+
+ reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+ reg &= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
+
+ return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg ? 1 : 0);
+}
+
+static void aspeed_vuart_set_sirq_polarity(struct aspeed_vuart *vuart,
+ bool polarity)
+{
+ u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+
+ if (polarity)
+ reg |= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
+ else
+ reg &= ~ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
+
+ writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
+}
+
+static ssize_t sirq_polarity_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct aspeed_vuart *vuart = dev_get_drvdata(dev);
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 0, &val);
+ if (err)
+ return err;
+
+ aspeed_vuart_set_sirq_polarity(vuart, val != 0);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(sirq_polarity);
+
static struct attribute *aspeed_vuart_attrs[] = {
&dev_attr_sirq.attr,
+ &dev_attr_sirq_polarity.attr,
&dev_attr_lpc_address.attr,
NULL,
};
@@ -302,8 +350,30 @@ static int aspeed_vuart_handle_irq(struct uart_port *port)
return 1;
}
+static void aspeed_vuart_auto_configure_sirq_polarity(
+ struct aspeed_vuart *vuart, struct device_node *syscon_np,
+ u32 reg_offset, u32 reg_mask)
+{
+ struct regmap *regmap;
+ u32 value;
+
+ regmap = syscon_node_to_regmap(syscon_np);
+ if (IS_ERR(regmap)) {
+ dev_warn(vuart->dev,
+ "could not get regmap for aspeed,sirq-polarity-sense\n");
+ return;
+ }
+ if (regmap_read(regmap, reg_offset, &value)) {
+ dev_warn(vuart->dev, "could not read hw strap table\n");
+ return;
+ }
+
+ aspeed_vuart_set_sirq_polarity(vuart, (value & reg_mask) == 0);
+}
+
static int aspeed_vuart_probe(struct platform_device *pdev)
{
+ struct of_phandle_args sirq_polarity_sense_args;
struct uart_8250_port port;
struct aspeed_vuart *vuart;
struct device_node *np;
@@ -402,6 +472,20 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
vuart->line = rc;
+ rc = of_parse_phandle_with_fixed_args(
+ np, "aspeed,sirq-polarity-sense", 2, 0,
+ &sirq_polarity_sense_args);
+ if (rc < 0) {
+ dev_dbg(&pdev->dev,
+ "aspeed,sirq-polarity-sense property not found\n");
+ } else {
+ aspeed_vuart_auto_configure_sirq_polarity(
+ vuart, sirq_polarity_sense_args.np,
+ sirq_polarity_sense_args.args[0],
+ BIT(sirq_polarity_sense_args.args[1]));
+ of_node_put(sirq_polarity_sense_args.np);
+ }
+
aspeed_vuart_set_enabled(vuart, true);
aspeed_vuart_set_host_tx_discard(vuart, true);
platform_set_drvdata(pdev, vuart);