Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/tty/serial/8250/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 8 kB image not shown  

Quelle  8250_ingenic.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2010 Lars-Peter Clausen <lars@metafoo.de>
 * Copyright (C) 2015 Imagination Technologies
 *
 * Ingenic SoC UART support
 */


#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/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 early_in(struct uart_port *port, int offset)
{
 return readl(port->membase + (offset << 2));
}

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

static void ingenic_early_console_putc(struct uart_port *port, unsigned char c)
{
 u16 lsr;

 do {
  lsr = early_in(port, UART_LSR);
 } while ((lsr & UART_LSR_TEMT) == 0);

 early_out(port, UART_TX, c);
}

static void 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);
}

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);
}

static int __init ingenic_earlycon_setup_tail(struct earlycon_device *dev,
           const char *opt)
{
 struct uart_port *port = &dev->port;
 unsigned int divisor;
 int baud = 115200;

 if (!dev->port.membase)
  return -ENODEV;

 if (opt) {
  unsigned int parity, bits, flow; /* unused for now */

  uart_parse_options(opt, &baud, &parity, &bits, &flow);
 }

 if (dev->baud)
  baud = dev->baud;
 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;
}

static int __init ingenic_early_console_setup(struct earlycon_device *dev,
           const char *opt)
{
 ingenic_early_console_setup_clock(dev);

 return ingenic_earlycon_setup_tail(dev, opt);
}

static int __init jz4750_early_console_setup(struct earlycon_device *dev,
          const char *opt)
{
 /*
 * JZ4750/55/60 have an optional /2 divider between the EXT
 * oscillator and some peripherals including UART, which will
 * be enabled if using a 24 MHz oscillator, and disabled when
 * using a 12 MHz oscillator.
 */

 ingenic_early_console_setup_clock(dev);
 if (dev->port.uartclk >= 16000000)
  dev->port.uartclk /= 2;

 return ingenic_earlycon_setup_tail(dev, opt);
}

OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart",
      ingenic_early_console_setup);

OF_EARLYCON_DECLARE(jz4750_uart, "ingenic,jz4750-uart",
      jz4750_early_console_setup);

OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart",
      ingenic_early_console_setup);

OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart",
      ingenic_early_console_setup);

OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
      ingenic_early_console_setup);

OF_EARLYCON_DECLARE(x1000_uart, "ingenic,x1000-uart",
      ingenic_early_console_setup);

static void ingenic_uart_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
 u32 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));
}

static u32 ingenic_uart_serial_in(struct uart_port *p, unsigned int offset)
{
 u8 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;
}

static int ingenic_uart_probe(struct platform_device *pdev)
{
 struct uart_8250_port uart = {};
 struct ingenic_uart_data *data;
 const struct ingenic_uart_config *cdata;
 struct resource *regs;
 int err;

 cdata = of_device_get_match_data(&pdev->dev);
 if (!cdata) {
  dev_err(&pdev->dev, "Error: No device match found\n");
  return -ENODEV;
 }

 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 if (!regs) {
  dev_err(&pdev->dev, "no registers 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.mapbase = regs->start;
 uart.port.serial_out = ingenic_uart_serial_out;
 uart.port.serial_in = ingenic_uart_serial_in;
 uart.port.dev = &pdev->dev;
 uart.tx_loadsz = cdata->tx_loadsz;
 uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE;

 err = uart_read_port_properties(&uart.port);
 if (err)
  return err;

 uart.port.regshift = 2;
 uart.port.fifosize = cdata->fifosize;

 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))
  return dev_err_probe(&pdev->dev, PTR_ERR(data->clk_module),
         "unable to get module clock\n");

 data->clk_baud = devm_clk_get(&pdev->dev, "baud");
 if (IS_ERR(data->clk_baud))
  return dev_err_probe(&pdev->dev, PTR_ERR(data->clk_baud),
         "unable to get baud clock\n");

 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;
}

static void 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);
}

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 ingenic_uart_config x1000_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,jz4750-uart", .data = &jz4760_uart_config },
 { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
 { .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config },
 { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
 { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config },
 { .compatible = "ingenic,x1000-uart", .data = &x1000_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");

Messung V0.5
C=97 H=90 G=93

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.