cregit-Linux how code gets into the kernel

Release 4.11 drivers/tty/serial/8250/8250_ingenic.c

/*
 * Copyright (C) 2010 Lars-Peter Clausen <lars@metafoo.de>
 * Copyright (C) 2015 Imagination Technologies
 *
 * Ingenic SoC UART support
 *
 * 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 the
 * Free Software Foundation;  either version 2 of the   License, or (at your
 * option) any later version.
 *
 * You should have received a copy of the  GNU General Public License along
 * with this program; if not, write  to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/clk.h>
#include <linux/console.h>
#include <linux/io.h>
#include <linux/libfdt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>

#include "8250.h"

/** ingenic_uart_config: SOC specific config data. */

struct ingenic_uart_config {
	
int tx_loadsz;
	
int fifosize;
};


struct ingenic_uart_data {
	
struct clk	*clk_module;
	
struct clk	*clk_baud;
	
int		line;
};


static const struct of_device_id of_match[];


#define UART_FCR_UME	BIT(4)


#define UART_MCR_MDCE	BIT(7)

#define UART_MCR_FCM	BIT(6)


static struct earlycon_device *early_device;


static uint8_t __init early_in(struct uart_port *port, int offset) { return readl(port->membase + (offset << 2)); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Burton29100.00%1100.00%
Total29100.00%1100.00%


static void __init early_out(struct uart_port *port, int offset, uint8_t value) { writel(value, port->membase + (offset << 2)); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Burton33100.00%1100.00%
Total33100.00%1100.00%


static void __init ingenic_early_console_putc(struct uart_port *port, int c) { uint8_t lsr; do { lsr = early_in(port, UART_LSR); } while ((lsr & UART_LSR_TEMT) == 0); early_out(port, UART_TX, c); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Burton50100.00%1100.00%
Total50100.00%1100.00%


static void __init ingenic_early_console_write(struct console *console, const char *s, unsigned int count) { uart_console_write(&early_device->port, s, count, ingenic_early_console_putc); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Burton35100.00%1100.00%
Total35100.00%1100.00%


static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev) { void *fdt = initial_boot_params; const __be32 *prop; int offset; offset = fdt_path_offset(fdt, "/ext"); if (offset < 0) return; prop = fdt_getprop(fdt, offset, "clock-frequency", NULL); if (!prop) return; dev->port.uartclk = be32_to_cpup(prop); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Burton72100.00%1100.00%
Total72100.00%1100.00%


static int __init ingenic_early_console_setup(struct earlycon_device *dev, const char *opt) { struct uart_port *port = &dev->port; unsigned int baud, divisor; if (!dev->port.membase) return -ENODEV; ingenic_early_console_setup_clock(dev); baud = dev->baud ?: 115200; divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud); early_out(port, UART_IER, 0); early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); early_out(port, UART_DLL, 0); early_out(port, UART_DLM, 0); early_out(port, UART_LCR, UART_LCR_WLEN8); early_out(port, UART_FCR, UART_FCR_UME | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR | UART_FCR_ENABLE_FIFO); early_out(port, UART_MCR, UART_MCR_RTS | UART_MCR_DTR); early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); early_out(port, UART_DLL, divisor & 0xff); early_out(port, UART_DLM, (divisor >> 8) & 0xff); early_out(port, UART_LCR, UART_LCR_WLEN8); early_device = dev; dev->con->write = ingenic_early_console_write; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Burton207100.00%1100.00%
Total207100.00%1100.00%

EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", ingenic_early_console_setup); EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", ingenic_early_console_setup); EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", ingenic_early_console_setup);
static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) { int ier; switch (offset) { case UART_FCR: /* UART module enable */ value |= UART_FCR_UME; break; case UART_IER: /* * Enable receive timeout interrupt with the receive line * status interrupt. */ value |= (value & 0x4) << 2; break; case UART_MCR: /* * If we have enabled modem status IRQs we should enable * modem mode. */ ier = p->serial_in(p, UART_IER); if (ier & UART_IER_MSI) value |= UART_MCR_MDCE | UART_MCR_FCM; else value &= ~(UART_MCR_MDCE | UART_MCR_FCM); break; default: break; } writeb(value, p->membase + (offset << p->regshift)); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Burton6560.75%133.33%
Matt Redfearn4037.38%133.33%
Anton Wuerfel21.87%133.33%
Total107100.00%3100.00%


static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset) { unsigned int value; value = readb(p->membase + (offset << p->regshift)); /* Hide non-16550 compliant bits from higher levels */ switch (offset) { case UART_FCR: value &= ~UART_FCR_UME; break; case UART_MCR: value &= ~(UART_MCR_MDCE | UART_MCR_FCM); break; default: break; } return value; }

Contributors

PersonTokensPropCommitsCommitProp
Matt Redfearn70100.00%1100.00%
Total70100.00%1100.00%


static int ingenic_uart_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}; struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct ingenic_uart_data *data; const struct ingenic_uart_config *cdata; const struct of_device_id *match; int err, line; match = of_match_device(of_match, &pdev->dev); if (!match) { dev_err(&pdev->dev, "Error: No device match found\n"); return -ENODEV; } cdata = match->data; if (!regs || !irq) { dev_err(&pdev->dev, "no registers/irq defined\n"); return -EINVAL; } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; spin_lock_init(&uart.port.lock); uart.port.type = PORT_16550A; uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE; uart.port.iotype = UPIO_MEM; uart.port.mapbase = regs->start; uart.port.regshift = 2; uart.port.serial_out = ingenic_uart_serial_out; uart.port.serial_in = ingenic_uart_serial_in; uart.port.irq = irq->start; uart.port.dev = &pdev->dev; uart.port.fifosize = cdata->fifosize; uart.tx_loadsz = cdata->tx_loadsz; uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE; /* Check for a fixed line number */ line = of_alias_get_id(pdev->dev.of_node, "serial"); if (line >= 0) uart.port.line = line; uart.port.membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); if (!uart.port.membase) return -ENOMEM; data->clk_module = devm_clk_get(&pdev->dev, "module"); if (IS_ERR(data->clk_module)) { err = PTR_ERR(data->clk_module); if (err != -EPROBE_DEFER) dev_err(&pdev->dev, "unable to get module clock: %d\n", err); return err; } data->clk_baud = devm_clk_get(&pdev->dev, "baud"); if (IS_ERR(data->clk_baud)) { err = PTR_ERR(data->clk_baud); if (err != -EPROBE_DEFER) dev_err(&pdev->dev, "unable to get baud clock: %d\n", err); return err; } err = clk_prepare_enable(data->clk_module); if (err) { dev_err(&pdev->dev, "could not enable module clock: %d\n", err); goto out; } err = clk_prepare_enable(data->clk_baud); if (err) { dev_err(&pdev->dev, "could not enable baud clock: %d\n", err); goto out_disable_moduleclk; } uart.port.uartclk = clk_get_rate(data->clk_baud); data->line = serial8250_register_8250_port(&uart); if (data->line < 0) { err = data->line; goto out_disable_baudclk; } platform_set_drvdata(pdev, data); return 0; out_disable_baudclk: clk_disable_unprepare(data->clk_baud); out_disable_moduleclk: clk_disable_unprepare(data->clk_module); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Burton50185.35%133.33%
Matt Redfearn8614.65%266.67%
Total587100.00%3100.00%


static int ingenic_uart_remove(struct platform_device *pdev) { struct ingenic_uart_data *data = platform_get_drvdata(pdev); serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk_module); clk_disable_unprepare(data->clk_baud); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arnd Bergmann45100.00%1100.00%
Total45100.00%1100.00%

static const struct ingenic_uart_config jz4740_uart_config = { .tx_loadsz = 8, .fifosize = 16, }; static const struct ingenic_uart_config jz4760_uart_config = { .tx_loadsz = 16, .fifosize = 32, }; static const struct ingenic_uart_config jz4780_uart_config = { .tx_loadsz = 32, .fifosize = 64, }; static const struct of_device_id of_match[] = { { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config }, { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, of_match); static struct platform_driver ingenic_uart_platform_driver = { .driver = { .name = "ingenic-uart", .of_match_table = of_match, }, .probe = ingenic_uart_probe, .remove = ingenic_uart_remove, }; module_platform_driver(ingenic_uart_platform_driver); MODULE_AUTHOR("Paul Burton"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Ingenic SoC UART driver");

Overall Contributors

PersonTokensPropCommitsCommitProp
Paul Burton116274.68%116.67%
Matt Redfearn31420.18%233.33%
Arnd Bergmann754.82%116.67%
Paul Gortmaker30.19%116.67%
Anton Wuerfel20.13%116.67%
Total1556100.00%6100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.