From fd00d693cc6c0bfe61d638a820e4e9895560bcee Mon Sep 17 00:00:00 2001 From: Antony Pavlov Date: Tue, 29 Jul 2014 01:15:23 +0400 Subject: serial: add driver for Canon DIGIC UART Signed-off-by: Antony Pavlov Signed-off-by: Sascha Hauer --- drivers/serial/Kconfig | 4 ++ drivers/serial/Makefile | 1 + drivers/serial/serial_digic.c | 132 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 drivers/serial/serial_digic.c (limited to 'drivers/serial') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index f51c6e6b02..aa8833126c 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -129,4 +129,8 @@ config DRIVER_SERIAL_CADENCE help Say Y here if you have a Cadence serial IP core. +config DRIVER_SERIAL_DIGIC + bool "Canon DIGIC serial driver" + depends on ARCH_DIGIC + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index e1865f725a..2d0e98eed3 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_DRIVER_SERIAL_PXA) += serial_pxa.o obj-$(CONFIG_DRIVER_SERIAL_OMAP4_USBBOOT) += serial_omap4_usbboot.o obj-$(CONFIG_DRIVER_SERIAL_AUART) += serial_auart.o obj-$(CONFIG_DRIVER_SERIAL_CADENCE) += serial_cadence.o +obj-$(CONFIG_DRIVER_SERIAL_DIGIC) += serial_digic.o diff --git a/drivers/serial/serial_digic.c b/drivers/serial/serial_digic.c new file mode 100644 index 0000000000..235ea0ff47 --- /dev/null +++ b/drivers/serial/serial_digic.c @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2013, 2014 Antony Pavlov + * + * This file is part of barebox. + * See file CREDITS for list of people who contributed to this project. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + +#include + +/* + * This driver is based on the "Serial terminal" docs here: + * http://magiclantern.wikia.com/wiki/Register_Map#Misc_Registers + * + * See also disassembler output for Canon A1100IS firmware + * (version a1100_100c): + * * a outc-like function can be found at address 0xffff18f0; + * * a getc-like function can be found at address 0xffff192c. + */ + +static inline uint32_t digic_serial_readl(struct console_device *cdev, + uint32_t offset) +{ + void __iomem *base = cdev->dev->priv; + + return readl(base + offset); +} + +static inline void digic_serial_writel(struct console_device *cdev, + uint32_t value, uint32_t offset) +{ + void __iomem *base = cdev->dev->priv; + + writel(value, base + offset); +} + +static int digic_serial_setbaudrate(struct console_device *cdev, int baudrate) +{ + /* I don't know how to setup baudrate :( */ + + return 0; +} + +static void digic_serial_putc(struct console_device *cdev, char c) +{ + uint32_t status; + + do { + status = digic_serial_readl(cdev, DIGIC_UART_ST); + } while (!(status & DIGIC_UART_ST_TX_RDY)); + + digic_serial_writel(cdev, 0x06, DIGIC_UART_ST); + digic_serial_writel(cdev, c, DIGIC_UART_TX); +} + +static int digic_serial_getc(struct console_device *cdev) +{ + uint32_t status; + + do { + status = digic_serial_readl(cdev, DIGIC_UART_ST); + } while (!(status & DIGIC_UART_ST_RX_RDY)); + + digic_serial_writel(cdev, 0x01, DIGIC_UART_ST); + + return digic_serial_readl(cdev, DIGIC_UART_RX); +} + +static int digic_serial_tstc(struct console_device *cdev) +{ + uint32_t status = digic_serial_readl(cdev, DIGIC_UART_ST); + + return ((status & DIGIC_UART_ST_RX_RDY) != 0); + + /* + * Canon folks use additional check, something like this: + * + * if (digic_serial_readl(cdev, DIGIC_UART_ST) & 0x38) { + * digic_serial_writel(cdev, 0x38, DIGIC_UART_ST); + * return 0; + * } + * + * But I know nothing about these magic bits in the status register... + * + */ +} + +static int digic_serial_probe(struct device_d *dev) +{ + struct console_device *cdev; + + cdev = xzalloc(sizeof(struct console_device)); + dev->priv = dev_request_mem_region(dev, 0); + cdev->dev = dev; + cdev->tstc = &digic_serial_tstc; + cdev->putc = &digic_serial_putc; + cdev->getc = &digic_serial_getc; + cdev->setbrg = &digic_serial_setbaudrate; + + console_register(cdev); + + return 0; +} + +static __maybe_unused struct of_device_id digic_serial_dt_ids[] = { + { + .compatible = "canon,digic-uart", + }, { + /* sentinel */ + } +}; + +static struct driver_d digic_serial_driver = { + .name = "digic-uart", + .probe = digic_serial_probe, + .of_compatible = DRV_OF_COMPAT(digic_serial_dt_ids), +}; +console_platform_driver(digic_serial_driver); -- cgit v1.2.3