mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'tty-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial updates from Greg KH:
"Here are some small updates for tty/serial drivers for 6.18-rc1.
Not many changes overall, just the usual:
- abi cleanups and reworking of the tty functions by Jiri by adding
console lock guard logic
- 8250_platform driver updates
- qcom-geni driver updates
- other minor serial driver updates
- some more vt escape codes added
All of these have been in linux-next for a while with no reported
issues"
* tag 'tty-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (43 commits)
tty: serial: fix help message for SERIAL_CPM
serial: 8250: omap: Support wakeup pinctrl state on suspend
dt-bindings: serial: 8250_omap: Add wakeup pinctrl state
serial: max310x: improve interrupt handling
vt: move vc_saved_screen to within tty allocated judgment
Revert "m68k: make HPDCA and HPAPCI bools"
tty: remove redundant condition checks
tty/vt: Add missing return value for VT_RESIZE in vt_ioctl()
vt: remove redundant check on vc_mode in con_font_set()
serial: qcom-geni: Add DFS clock mode support to GENI UART driver
m68k: make HPDCA and HPAPCI bools
tty: n_gsm: Don't block input queue by waiting MSC
serial: qcom-geni: Fix off-by-one error in ida_alloc_range()
serdev: Drop dev_pm_domain_detach() call
serial: sc16is7xx: drop redundant conversion to bool
vt: add support for smput/rmput escape codes
serial: stm32: allow selecting console when the driver is module
serial: 8250_core: fix coding style issue
tty: serial: Modify the use of dev_err_probe()
s390/char/con3270: use tty_port_tty guard()
...
This commit is contained in:
@@ -71,6 +71,22 @@ properties:
|
||||
overrun-throttle-ms: true
|
||||
wakeup-source: true
|
||||
|
||||
pinctrl-0:
|
||||
description: Default pinctrl state
|
||||
|
||||
pinctrl-1:
|
||||
description: Wakeup pinctrl state
|
||||
|
||||
pinctrl-names:
|
||||
description:
|
||||
When present should contain at least "default" describing the default pin
|
||||
states. The second state called "wakeup" describes the pins in their
|
||||
wakeup configuration required to exit sleep states.
|
||||
minItems: 1
|
||||
items:
|
||||
- const: default
|
||||
- const: wakeup
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -221,3 +221,35 @@ static int __init sgi_ds1286_devinit(void)
|
||||
}
|
||||
|
||||
device_initcall(sgi_ds1286_devinit);
|
||||
|
||||
#define SGI_ZILOG_BASE (HPC3_CHIP0_BASE + \
|
||||
offsetof(struct hpc3_regs, pbus_extregs[6]) + \
|
||||
offsetof(struct sgioc_regs, uart))
|
||||
|
||||
static struct resource sgi_zilog_resources[] = {
|
||||
{
|
||||
.start = SGI_ZILOG_BASE,
|
||||
.end = SGI_ZILOG_BASE + 15,
|
||||
.flags = IORESOURCE_MEM
|
||||
},
|
||||
{
|
||||
.start = SGI_SERIAL_IRQ,
|
||||
.end = SGI_SERIAL_IRQ,
|
||||
.flags = IORESOURCE_IRQ
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device zilog_device = {
|
||||
.name = "ip22zilog",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(sgi_zilog_resources),
|
||||
.resource = sgi_zilog_resources,
|
||||
};
|
||||
|
||||
|
||||
static int __init sgi_zilog_devinit(void)
|
||||
{
|
||||
return platform_device_register(&zilog_device);
|
||||
}
|
||||
|
||||
device_initcall(sgi_zilog_devinit);
|
||||
|
||||
@@ -970,8 +970,6 @@ static void tty3270_resize(struct raw3270_view *view,
|
||||
char **old_rcl_lines, **new_rcl_lines;
|
||||
char *old_prompt, *new_prompt;
|
||||
char *old_input, *new_input;
|
||||
struct tty_struct *tty;
|
||||
struct winsize ws;
|
||||
size_t prompt_sz;
|
||||
int new_allocated, old_allocated = tp->allocated_lines;
|
||||
|
||||
@@ -1023,14 +1021,14 @@ static void tty3270_resize(struct raw3270_view *view,
|
||||
kfree(old_prompt);
|
||||
tty3270_free_recall(old_rcl_lines);
|
||||
tty3270_set_timer(tp, 1);
|
||||
/* Informat tty layer about new size */
|
||||
tty = tty_port_tty_get(&tp->port);
|
||||
if (!tty)
|
||||
return;
|
||||
ws.ws_row = tty3270_tty_rows(tp);
|
||||
ws.ws_col = tp->view.cols;
|
||||
tty_do_resize(tty, &ws);
|
||||
tty_kref_put(tty);
|
||||
/* Inform the tty layer about new size */
|
||||
scoped_guard(tty_port_tty, &tp->port) {
|
||||
struct winsize ws = {
|
||||
.ws_row = tty3270_tty_rows(tp),
|
||||
.ws_col = tp->view.cols,
|
||||
};
|
||||
tty_do_resize(scoped_tty(), &ws);
|
||||
}
|
||||
return;
|
||||
out_screen:
|
||||
tty3270_free_screen(screen, new_rows);
|
||||
|
||||
@@ -184,7 +184,7 @@ static void hvc_console_print(struct console *co, const char *b,
|
||||
hvc_console_flush(cons_ops[index],
|
||||
vtermnos[index]);
|
||||
}
|
||||
} else if (r > 0) {
|
||||
} else {
|
||||
i -= r;
|
||||
if (i > 0)
|
||||
memmove(c, c+r, i);
|
||||
|
||||
+106
-159
File diff suppressed because it is too large
Load Diff
+24
-1
@@ -461,6 +461,7 @@ static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg);
|
||||
static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr);
|
||||
static void gsmld_write_trigger(struct gsm_mux *gsm);
|
||||
static void gsmld_write_task(struct work_struct *work);
|
||||
static int gsm_modem_send_initial_msc(struct gsm_dlci *dlci);
|
||||
|
||||
/**
|
||||
* gsm_fcs_add - update FCS
|
||||
@@ -2174,7 +2175,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
|
||||
pr_debug("DLCI %d goes open.\n", dlci->addr);
|
||||
/* Send current modem state */
|
||||
if (dlci->addr) {
|
||||
gsm_modem_update(dlci, 0);
|
||||
gsm_modem_send_initial_msc(dlci);
|
||||
} else {
|
||||
/* Start keep-alive control */
|
||||
gsm->ka_num = 0;
|
||||
@@ -4161,6 +4162,28 @@ static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
|
||||
return gsm_control_wait(dlci->gsm, ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_modem_send_initial_msc - Send initial modem status message
|
||||
*
|
||||
* @dlci channel
|
||||
*
|
||||
* Send an initial MSC message after DLCI open to set the initial
|
||||
* modem status lines. This is only done for basic mode.
|
||||
* Does not wait for a response as we cannot block the input queue
|
||||
* processing.
|
||||
*/
|
||||
static int gsm_modem_send_initial_msc(struct gsm_dlci *dlci)
|
||||
{
|
||||
u8 modembits[2];
|
||||
|
||||
if (dlci->adaption != 1 || dlci->gsm->encoding != GSM_BASIC_OPT)
|
||||
return 0;
|
||||
|
||||
modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */
|
||||
modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
|
||||
return gsm_control_command(dlci->gsm, CMD_MSC, (const u8 *)&modembits, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_modem_update - send modem status line state
|
||||
* @dlci: channel
|
||||
|
||||
@@ -399,15 +399,12 @@ static int serdev_drv_probe(struct device *dev)
|
||||
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
|
||||
int ret;
|
||||
|
||||
ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON);
|
||||
ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON |
|
||||
PD_FLAG_DETACH_POWER_OFF);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sdrv->probe(to_serdev_device(dev));
|
||||
if (ret)
|
||||
dev_pm_domain_detach(dev, true);
|
||||
|
||||
return ret;
|
||||
return sdrv->probe(to_serdev_device(dev));
|
||||
}
|
||||
|
||||
static void serdev_drv_remove(struct device *dev)
|
||||
@@ -415,8 +412,6 @@ static void serdev_drv_remove(struct device *dev)
|
||||
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
|
||||
if (sdrv->remove)
|
||||
sdrv->remove(to_serdev_device(dev));
|
||||
|
||||
dev_pm_domain_detach(dev, true);
|
||||
}
|
||||
|
||||
static const struct bus_type serdev_bus_type = {
|
||||
|
||||
@@ -186,6 +186,11 @@ static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up,
|
||||
|
||||
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
|
||||
|
||||
void serial8250_rpm_get(struct uart_8250_port *p);
|
||||
void serial8250_rpm_put(struct uart_8250_port *p);
|
||||
DEFINE_GUARD(serial8250_rpm, struct uart_8250_port *,
|
||||
serial8250_rpm_get(_T), serial8250_rpm_put(_T));
|
||||
|
||||
static inline u32 serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return up->dl_read(up);
|
||||
|
||||
@@ -72,7 +72,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
|
||||
struct list_head *l, *end = NULL;
|
||||
int pass_counter = 0, handled = 0;
|
||||
|
||||
spin_lock(&i->lock);
|
||||
guard(spinlock)(&i->lock);
|
||||
|
||||
l = i->head;
|
||||
do {
|
||||
@@ -91,8 +91,6 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
|
||||
break;
|
||||
} while (l != end);
|
||||
|
||||
spin_unlock(&i->lock);
|
||||
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
@@ -132,22 +130,19 @@ static struct irq_info *serial_get_or_create_irq_info(const struct uart_8250_por
|
||||
{
|
||||
struct irq_info *i;
|
||||
|
||||
mutex_lock(&hash_mutex);
|
||||
guard(mutex)(&hash_mutex);
|
||||
|
||||
hash_for_each_possible(irq_lists, i, node, up->port.irq)
|
||||
if (i->irq == up->port.irq)
|
||||
goto unlock;
|
||||
return i;
|
||||
|
||||
i = kzalloc(sizeof(*i), GFP_KERNEL);
|
||||
if (i == NULL) {
|
||||
i = ERR_PTR(-ENOMEM);
|
||||
goto unlock;
|
||||
}
|
||||
if (i == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock_init(&i->lock);
|
||||
i->irq = up->port.irq;
|
||||
hash_add(irq_lists, &i->node, i->irq);
|
||||
unlock:
|
||||
mutex_unlock(&hash_mutex);
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -161,23 +156,21 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
|
||||
if (IS_ERR(i))
|
||||
return PTR_ERR(i);
|
||||
|
||||
spin_lock_irq(&i->lock);
|
||||
scoped_guard(spinlock_irq, &i->lock) {
|
||||
if (i->head) {
|
||||
list_add(&up->list, i->head);
|
||||
|
||||
if (i->head) {
|
||||
list_add(&up->list, i->head);
|
||||
spin_unlock_irq(&i->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
} else {
|
||||
INIT_LIST_HEAD(&up->list);
|
||||
i->head = &up->list;
|
||||
spin_unlock_irq(&i->lock);
|
||||
ret = request_irq(up->port.irq, serial8250_interrupt,
|
||||
up->port.irqflags, up->port.name, i);
|
||||
if (ret < 0)
|
||||
serial_do_unlink(i, up);
|
||||
}
|
||||
|
||||
ret = request_irq(up->port.irq, serial8250_interrupt, up->port.irqflags, up->port.name, i);
|
||||
if (ret < 0)
|
||||
serial_do_unlink(i, up);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -185,20 +178,22 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
|
||||
{
|
||||
struct irq_info *i;
|
||||
|
||||
mutex_lock(&hash_mutex);
|
||||
guard(mutex)(&hash_mutex);
|
||||
|
||||
hash_for_each_possible(irq_lists, i, node, up->port.irq)
|
||||
if (i->irq == up->port.irq)
|
||||
break;
|
||||
if (i->irq == up->port.irq) {
|
||||
if (WARN_ON(i->head == NULL))
|
||||
return;
|
||||
|
||||
BUG_ON(i == NULL);
|
||||
BUG_ON(i->head == NULL);
|
||||
if (list_empty(i->head))
|
||||
free_irq(up->port.irq, i);
|
||||
|
||||
if (list_empty(i->head))
|
||||
free_irq(up->port.irq, i);
|
||||
serial_do_unlink(i, up);
|
||||
|
||||
serial_do_unlink(i, up);
|
||||
mutex_unlock(&hash_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -307,7 +302,7 @@ static void univ8250_release_irq(struct uart_8250_port *up)
|
||||
serial_unlink_irq_chain(up);
|
||||
}
|
||||
|
||||
const struct uart_ops *univ8250_port_base_ops = NULL;
|
||||
const struct uart_ops *univ8250_port_base_ops;
|
||||
struct uart_ops univ8250_port_ops;
|
||||
|
||||
static const struct uart_8250_ops univ8250_driver_ops = {
|
||||
@@ -670,16 +665,12 @@ static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_
|
||||
|
||||
static void serial_8250_overrun_backoff_work(struct work_struct *work)
|
||||
{
|
||||
struct uart_8250_port *up =
|
||||
container_of(to_delayed_work(work), struct uart_8250_port,
|
||||
overrun_backoff);
|
||||
struct uart_port *port = &up->port;
|
||||
unsigned long flags;
|
||||
struct uart_8250_port *up = container_of(to_delayed_work(work), struct uart_8250_port,
|
||||
overrun_backoff);
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
guard(uart_port_lock_irqsave)(&up->port);
|
||||
up->ier |= UART_IER_RLSI | UART_IER_RDI;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -698,12 +689,12 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
|
||||
int serial8250_register_8250_port(const struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_8250_port *uart;
|
||||
int ret = -ENOSPC;
|
||||
int ret;
|
||||
|
||||
if (up->port.uartclk == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&serial_mutex);
|
||||
guard(mutex)(&serial_mutex);
|
||||
|
||||
uart = serial8250_find_match_or_unused(&up->port);
|
||||
if (!uart) {
|
||||
@@ -713,15 +704,13 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
|
||||
*/
|
||||
uart = serial8250_setup_port(nr_uarts);
|
||||
if (!uart)
|
||||
goto unlock;
|
||||
return -ENOSPC;
|
||||
nr_uarts++;
|
||||
}
|
||||
|
||||
/* Check if it is CIR already. We check this below again, see there why. */
|
||||
if (uart->port.type == PORT_8250_CIR) {
|
||||
ret = -ENODEV;
|
||||
goto unlock;
|
||||
}
|
||||
if (uart->port.type == PORT_8250_CIR)
|
||||
return -ENODEV;
|
||||
|
||||
if (uart->port.dev)
|
||||
uart_remove_one_port(&serial8250_reg, &uart->port);
|
||||
@@ -855,14 +844,10 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
|
||||
uart->overrun_backoff_time_ms = 0;
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&serial_mutex);
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
uart->port.dev = NULL;
|
||||
mutex_unlock(&serial_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(serial8250_register_8250_port);
|
||||
@@ -878,14 +863,11 @@ void serial8250_unregister_port(int line)
|
||||
{
|
||||
struct uart_8250_port *uart = &serial8250_ports[line];
|
||||
|
||||
mutex_lock(&serial_mutex);
|
||||
guard(mutex)(&serial_mutex);
|
||||
|
||||
if (uart->em485) {
|
||||
unsigned long flags;
|
||||
|
||||
uart_port_lock_irqsave(&uart->port, &flags);
|
||||
guard(uart_port_lock_irqsave)(&uart->port);
|
||||
serial8250_em485_destroy(uart);
|
||||
uart_port_unlock_irqrestore(&uart->port, flags);
|
||||
}
|
||||
|
||||
uart_remove_one_port(&serial8250_reg, &uart->port);
|
||||
@@ -901,7 +883,6 @@ void serial8250_unregister_port(int line)
|
||||
} else {
|
||||
uart->port.dev = NULL;
|
||||
}
|
||||
mutex_unlock(&serial_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(serial8250_unregister_port);
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
@@ -145,6 +147,9 @@ struct omap8250_priv {
|
||||
spinlock_t rx_dma_lock;
|
||||
bool rx_dma_broken;
|
||||
bool throttled;
|
||||
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pinctrl_wakeup;
|
||||
};
|
||||
|
||||
struct omap8250_dma_params {
|
||||
@@ -369,18 +374,12 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
|
||||
serial8250_em485_stop_tx(up, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have
|
||||
* some differences in how we want to handle flow control.
|
||||
*/
|
||||
static void omap_8250_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
const struct ktermios *old)
|
||||
static void omap_8250_set_termios_atomic(struct uart_port *port, struct ktermios *termios,
|
||||
const struct ktermios *old, unsigned int baud)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct omap8250_priv *priv = port->private_data;
|
||||
unsigned char cval = 0;
|
||||
unsigned int baud;
|
||||
u8 cval;
|
||||
|
||||
cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag));
|
||||
|
||||
@@ -393,20 +392,14 @@ static void omap_8250_set_termios(struct uart_port *port,
|
||||
if (termios->c_cflag & CMSPAR)
|
||||
cval |= UART_LCR_SPAR;
|
||||
|
||||
/*
|
||||
* Ask the core to calculate the divisor for us.
|
||||
*/
|
||||
baud = uart_get_baud_rate(port, termios, old,
|
||||
port->uartclk / 16 / UART_DIV_MAX,
|
||||
port->uartclk / 13);
|
||||
omap_8250_get_divisor(port, baud, priv);
|
||||
|
||||
/*
|
||||
* Ok, we're now changing the port state. Do it with
|
||||
* interrupts disabled.
|
||||
*/
|
||||
pm_runtime_get_sync(port->dev);
|
||||
uart_port_lock_irq(port);
|
||||
guard(serial8250_rpm)(up);
|
||||
guard(uart_port_lock_irq)(port);
|
||||
|
||||
/*
|
||||
* Update the per-port timeout.
|
||||
@@ -514,10 +507,27 @@ static void omap_8250_set_termios(struct uart_port *port,
|
||||
}
|
||||
}
|
||||
omap8250_restore_regs(up);
|
||||
}
|
||||
|
||||
uart_port_unlock_irq(&up->port);
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
/*
|
||||
* OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have
|
||||
* some differences in how we want to handle flow control.
|
||||
*/
|
||||
static void omap_8250_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
const struct ktermios *old)
|
||||
{
|
||||
struct omap8250_priv *priv = port->private_data;
|
||||
unsigned int baud;
|
||||
|
||||
/*
|
||||
* Ask the core to calculate the divisor for us.
|
||||
*/
|
||||
baud = uart_get_baud_rate(port, termios, old,
|
||||
port->uartclk / 16 / UART_DIV_MAX,
|
||||
port->uartclk / 13);
|
||||
|
||||
omap_8250_set_termios_atomic(port, termios, old, baud);
|
||||
|
||||
/* calculate wakeup latency constraint */
|
||||
priv->calc_latency = USEC_PER_SEC * 64 * 8 / baud;
|
||||
@@ -537,10 +547,9 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state,
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
u8 efr;
|
||||
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
guard(serial8250_rpm)(up);
|
||||
/* Synchronize UART_IER access against the console. */
|
||||
uart_port_lock_irq(port);
|
||||
guard(uart_port_lock_irq)(port);
|
||||
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
efr = serial_in(up, UART_EFR);
|
||||
@@ -551,11 +560,6 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state,
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
serial_out(up, UART_EFR, efr);
|
||||
serial_out(up, UART_LCR, 0);
|
||||
|
||||
uart_port_unlock_irq(port);
|
||||
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
}
|
||||
|
||||
static void omap_serial_fill_features_erratas(struct uart_8250_port *up,
|
||||
@@ -727,7 +731,11 @@ static int omap_8250_startup(struct uart_port *port)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(port->dev);
|
||||
#ifdef CONFIG_PM
|
||||
up->capabilities |= UART_CAP_RPM;
|
||||
#endif
|
||||
|
||||
guard(serial8250_rpm)(up);
|
||||
|
||||
serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
|
||||
|
||||
@@ -750,14 +758,10 @@ static int omap_8250_startup(struct uart_port *port)
|
||||
}
|
||||
|
||||
/* Synchronize UART_IER access against the console. */
|
||||
uart_port_lock_irq(port);
|
||||
up->ier = UART_IER_RLSI | UART_IER_RDI;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
uart_port_unlock_irq(port);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
up->capabilities |= UART_CAP_RPM;
|
||||
#endif
|
||||
scoped_guard(uart_port_lock_irq, port) {
|
||||
up->ier = UART_IER_RLSI | UART_IER_RDI;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
}
|
||||
|
||||
/* Enable module level wake up */
|
||||
priv->wer = OMAP_UART_WER_MOD_WKUP;
|
||||
@@ -766,15 +770,12 @@ static int omap_8250_startup(struct uart_port *port)
|
||||
serial_out(up, UART_OMAP_WER, priv->wer);
|
||||
|
||||
if (up->dma && !(priv->habit & UART_HAS_EFR2)) {
|
||||
uart_port_lock_irq(port);
|
||||
guard(uart_port_lock_irq)(port);
|
||||
up->dma->rx_dma(up);
|
||||
uart_port_unlock_irq(port);
|
||||
}
|
||||
|
||||
enable_irq(port->irq);
|
||||
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -783,7 +784,7 @@ static void omap_8250_shutdown(struct uart_port *port)
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct omap8250_priv *priv = port->private_data;
|
||||
|
||||
pm_runtime_get_sync(port->dev);
|
||||
guard(serial8250_rpm)(up);
|
||||
|
||||
flush_work(&priv->qos_work);
|
||||
if (up->dma)
|
||||
@@ -794,10 +795,11 @@ static void omap_8250_shutdown(struct uart_port *port)
|
||||
serial_out(up, UART_OMAP_EFR2, 0x0);
|
||||
|
||||
/* Synchronize UART_IER access against the console. */
|
||||
uart_port_lock_irq(port);
|
||||
up->ier = 0;
|
||||
serial_out(up, UART_IER, 0);
|
||||
uart_port_unlock_irq(port);
|
||||
scoped_guard(uart_port_lock_irq, port) {
|
||||
up->ier = 0;
|
||||
serial_out(up, UART_IER, 0);
|
||||
}
|
||||
|
||||
disable_irq_nosync(port->irq);
|
||||
dev_pm_clear_wake_irq(port->dev);
|
||||
|
||||
@@ -810,46 +812,33 @@ static void omap_8250_shutdown(struct uart_port *port)
|
||||
if (up->lcr & UART_LCR_SBC)
|
||||
serial_out(up, UART_LCR, up->lcr & ~UART_LCR_SBC);
|
||||
serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
|
||||
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
}
|
||||
|
||||
static void omap_8250_throttle(struct uart_port *port)
|
||||
{
|
||||
struct omap8250_priv *priv = port->private_data;
|
||||
unsigned long flags;
|
||||
|
||||
pm_runtime_get_sync(port->dev);
|
||||
guard(serial8250_rpm)(up_to_u8250p(port));
|
||||
guard(uart_port_lock_irqsave)(port);
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
port->ops->stop_rx(port);
|
||||
priv->throttled = true;
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
}
|
||||
|
||||
static void omap_8250_unthrottle(struct uart_port *port)
|
||||
{
|
||||
struct omap8250_priv *priv = port->private_data;
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned long flags;
|
||||
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
guard(serial8250_rpm)(up);
|
||||
/* Synchronize UART_IER access against the console. */
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
guard(uart_port_lock_irqsave)(port);
|
||||
|
||||
priv->throttled = false;
|
||||
if (up->dma)
|
||||
up->dma->rx_dma(up);
|
||||
up->ier |= UART_IER_RLSI | UART_IER_RDI;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
}
|
||||
|
||||
static int omap8250_rs485_config(struct uart_port *port,
|
||||
@@ -987,30 +976,26 @@ static void __dma_rx_complete(void *param)
|
||||
struct omap8250_priv *priv = p->port.private_data;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct dma_tx_state state;
|
||||
unsigned long flags;
|
||||
|
||||
/* Synchronize UART_IER access against the console. */
|
||||
uart_port_lock_irqsave(&p->port, &flags);
|
||||
guard(uart_port_lock_irqsave)(&p->port);
|
||||
|
||||
/*
|
||||
* If the tx status is not DMA_COMPLETE, then this is a delayed
|
||||
* completion callback. A previous RX timeout flush would have
|
||||
* already pushed the data, so exit.
|
||||
*/
|
||||
if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) !=
|
||||
DMA_COMPLETE) {
|
||||
uart_port_unlock_irqrestore(&p->port, flags);
|
||||
if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) != DMA_COMPLETE)
|
||||
return;
|
||||
}
|
||||
__dma_rx_do_complete(p);
|
||||
if (!priv->throttled) {
|
||||
p->ier |= UART_IER_RLSI | UART_IER_RDI;
|
||||
serial_out(p, UART_IER, p->ier);
|
||||
if (!(priv->habit & UART_HAS_EFR2))
|
||||
omap_8250_rx_dma(p);
|
||||
}
|
||||
|
||||
uart_port_unlock_irqrestore(&p->port, flags);
|
||||
__dma_rx_do_complete(p);
|
||||
if (priv->throttled)
|
||||
return;
|
||||
|
||||
p->ier |= UART_IER_RLSI | UART_IER_RDI;
|
||||
serial_out(p, UART_IER, p->ier);
|
||||
if (!(priv->habit & UART_HAS_EFR2))
|
||||
omap_8250_rx_dma(p);
|
||||
}
|
||||
|
||||
static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
|
||||
@@ -1108,14 +1093,13 @@ static void omap_8250_dma_tx_complete(void *param)
|
||||
struct uart_8250_port *p = param;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct tty_port *tport = &p->port.state->port;
|
||||
unsigned long flags;
|
||||
bool en_thri = false;
|
||||
struct omap8250_priv *priv = p->port.private_data;
|
||||
|
||||
dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
|
||||
uart_port_lock_irqsave(&p->port, &flags);
|
||||
guard(uart_port_lock_irqsave)(&p->port);
|
||||
|
||||
dma->tx_running = 0;
|
||||
|
||||
@@ -1143,8 +1127,6 @@ static void omap_8250_dma_tx_complete(void *param)
|
||||
dma->tx_err = 1;
|
||||
serial8250_set_THRI(p);
|
||||
}
|
||||
|
||||
uart_port_unlock_irqrestore(&p->port, flags);
|
||||
}
|
||||
|
||||
static int omap_8250_tx_dma(struct uart_8250_port *p)
|
||||
@@ -1372,6 +1354,18 @@ static int omap8250_no_handle_irq(struct uart_port *port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap8250_select_wakeup_pinctrl(struct device *dev,
|
||||
struct omap8250_priv *priv)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(priv->pinctrl_wakeup))
|
||||
return 0;
|
||||
|
||||
if (!device_may_wakeup(dev))
|
||||
return 0;
|
||||
|
||||
return pinctrl_select_state(priv->pinctrl, priv->pinctrl_wakeup);
|
||||
}
|
||||
|
||||
static struct omap8250_dma_params am654_dma = {
|
||||
.rx_size = SZ_2K,
|
||||
.rx_trigger = 1,
|
||||
@@ -1596,6 +1590,11 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
priv->line = ret;
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
|
||||
priv->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (!IS_ERR_OR_NULL(priv->pinctrl))
|
||||
priv->pinctrl_wakeup = pinctrl_lookup_state(priv->pinctrl, "wakeup");
|
||||
|
||||
return 0;
|
||||
err:
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
@@ -1653,6 +1652,13 @@ static int omap8250_suspend(struct device *dev)
|
||||
struct uart_8250_port *up = serial8250_get_port(priv->line);
|
||||
int err = 0;
|
||||
|
||||
err = omap8250_select_wakeup_pinctrl(dev, priv);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to select wakeup pinctrl, aborting suspend %pe\n",
|
||||
ERR_PTR(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
serial8250_suspend_port(priv->line);
|
||||
|
||||
err = pm_runtime_resume_and_get(dev);
|
||||
@@ -1674,6 +1680,13 @@ static int omap8250_resume(struct device *dev)
|
||||
struct uart_8250_port *up = serial8250_get_port(priv->line);
|
||||
int err;
|
||||
|
||||
err = pinctrl_select_default_state(dev);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to select default pinctrl state on resume: %pe\n",
|
||||
ERR_PTR(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
if (uart_console(&up->port) && console_suspend_enabled) {
|
||||
err = pm_runtime_force_resume(dev);
|
||||
if (err)
|
||||
@@ -1795,15 +1808,13 @@ static int omap8250_runtime_resume(struct device *dev)
|
||||
up = serial8250_get_port(priv->line);
|
||||
|
||||
if (up && omap8250_lost_context(up)) {
|
||||
uart_port_lock_irq(&up->port);
|
||||
guard(uart_port_lock_irq)(&up->port);
|
||||
omap8250_restore_regs(up);
|
||||
uart_port_unlock_irq(&up->port);
|
||||
}
|
||||
|
||||
if (up && up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2)) {
|
||||
uart_port_lock_irq(&up->port);
|
||||
guard(uart_port_lock_irq)(&up->port);
|
||||
omap_8250_rx_dma(up);
|
||||
uart_port_unlock_irq(&up->port);
|
||||
}
|
||||
|
||||
atomic_set(&priv->active, 1);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
@@ -110,41 +111,44 @@ void __init serial8250_isa_init_ports(void)
|
||||
static int serial8250_probe_acpi(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct uart_8250_port uart = { };
|
||||
struct resource *regs;
|
||||
int ret, line;
|
||||
|
||||
struct uart_8250_port *uart __free(kfree) = kzalloc(sizeof(*uart), GFP_KERNEL);
|
||||
if (!uart)
|
||||
return -ENOMEM;
|
||||
|
||||
regs = platform_get_mem_or_io(pdev, 0);
|
||||
if (!regs)
|
||||
return dev_err_probe(dev, -EINVAL, "no registers defined\n");
|
||||
|
||||
switch (resource_type(regs)) {
|
||||
case IORESOURCE_IO:
|
||||
uart.port.iobase = regs->start;
|
||||
uart->port.iobase = regs->start;
|
||||
break;
|
||||
case IORESOURCE_MEM:
|
||||
uart.port.mapbase = regs->start;
|
||||
uart.port.mapsize = resource_size(regs);
|
||||
uart.port.flags = UPF_IOREMAP;
|
||||
uart->port.mapbase = regs->start;
|
||||
uart->port.mapsize = resource_size(regs);
|
||||
uart->port.flags = UPF_IOREMAP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* default clock frequency */
|
||||
uart.port.uartclk = 1843200;
|
||||
uart.port.type = PORT_16550A;
|
||||
uart.port.dev = &pdev->dev;
|
||||
uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
|
||||
uart->port.uartclk = 1843200;
|
||||
uart->port.type = PORT_16550A;
|
||||
uart->port.dev = &pdev->dev;
|
||||
uart->port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
|
||||
|
||||
ret = uart_read_and_validate_port_properties(&uart.port);
|
||||
ret = uart_read_and_validate_port_properties(&uart->port);
|
||||
/* no interrupt -> fall back to polling */
|
||||
if (ret == -ENXIO)
|
||||
ret = 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
line = serial8250_register_8250_port(&uart);
|
||||
line = serial8250_register_8250_port(uart);
|
||||
if (line < 0)
|
||||
return line;
|
||||
|
||||
@@ -153,43 +157,44 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
|
||||
|
||||
static int serial8250_probe_platform(struct platform_device *dev, struct plat_serial8250_port *p)
|
||||
{
|
||||
struct uart_8250_port uart;
|
||||
int ret, i, irqflag = 0;
|
||||
|
||||
memset(&uart, 0, sizeof(uart));
|
||||
struct uart_8250_port *uart __free(kfree) = kzalloc(sizeof(*uart), GFP_KERNEL);
|
||||
if (!uart)
|
||||
return -ENOMEM;
|
||||
|
||||
if (share_irqs)
|
||||
irqflag = IRQF_SHARED;
|
||||
|
||||
for (i = 0; p && p->flags != 0; p++, i++) {
|
||||
uart.port.iobase = p->iobase;
|
||||
uart.port.membase = p->membase;
|
||||
uart.port.irq = p->irq;
|
||||
uart.port.irqflags = p->irqflags;
|
||||
uart.port.uartclk = p->uartclk;
|
||||
uart.port.regshift = p->regshift;
|
||||
uart.port.iotype = p->iotype;
|
||||
uart.port.flags = p->flags;
|
||||
uart.port.mapbase = p->mapbase;
|
||||
uart.port.mapsize = p->mapsize;
|
||||
uart.port.hub6 = p->hub6;
|
||||
uart.port.has_sysrq = p->has_sysrq;
|
||||
uart.port.private_data = p->private_data;
|
||||
uart.port.type = p->type;
|
||||
uart.bugs = p->bugs;
|
||||
uart.port.serial_in = p->serial_in;
|
||||
uart.port.serial_out = p->serial_out;
|
||||
uart.dl_read = p->dl_read;
|
||||
uart.dl_write = p->dl_write;
|
||||
uart.port.handle_irq = p->handle_irq;
|
||||
uart.port.handle_break = p->handle_break;
|
||||
uart.port.set_termios = p->set_termios;
|
||||
uart.port.set_ldisc = p->set_ldisc;
|
||||
uart.port.get_mctrl = p->get_mctrl;
|
||||
uart.port.pm = p->pm;
|
||||
uart.port.dev = &dev->dev;
|
||||
uart.port.irqflags |= irqflag;
|
||||
ret = serial8250_register_8250_port(&uart);
|
||||
uart->port.iobase = p->iobase;
|
||||
uart->port.membase = p->membase;
|
||||
uart->port.irq = p->irq;
|
||||
uart->port.irqflags = p->irqflags;
|
||||
uart->port.uartclk = p->uartclk;
|
||||
uart->port.regshift = p->regshift;
|
||||
uart->port.iotype = p->iotype;
|
||||
uart->port.flags = p->flags;
|
||||
uart->port.mapbase = p->mapbase;
|
||||
uart->port.mapsize = p->mapsize;
|
||||
uart->port.hub6 = p->hub6;
|
||||
uart->port.has_sysrq = p->has_sysrq;
|
||||
uart->port.private_data = p->private_data;
|
||||
uart->port.type = p->type;
|
||||
uart->bugs = p->bugs;
|
||||
uart->port.serial_in = p->serial_in;
|
||||
uart->port.serial_out = p->serial_out;
|
||||
uart->dl_read = p->dl_read;
|
||||
uart->dl_write = p->dl_write;
|
||||
uart->port.handle_irq = p->handle_irq;
|
||||
uart->port.handle_break = p->handle_break;
|
||||
uart->port.set_termios = p->set_termios;
|
||||
uart->port.set_ldisc = p->set_ldisc;
|
||||
uart->port.get_mctrl = p->get_mctrl;
|
||||
uart->port.pm = p->pm;
|
||||
uart->port.dev = &dev->dev;
|
||||
uart->port.irqflags |= irqflag;
|
||||
ret = serial8250_register_8250_port(uart);
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->dev, "unable to register port at index %d "
|
||||
"(IO%lx MEM%llx IRQ%d): %d\n", i,
|
||||
|
||||
+123
-177
File diff suppressed because it is too large
Load Diff
@@ -140,9 +140,8 @@ void rsa_enable(struct uart_8250_port *up)
|
||||
return;
|
||||
|
||||
if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
|
||||
uart_port_lock_irq(&up->port);
|
||||
guard(uart_port_lock_irq)(&up->port);
|
||||
__rsa_enable(up);
|
||||
uart_port_unlock_irq(&up->port);
|
||||
}
|
||||
if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
|
||||
serial_out(up, UART_RSA_FRR, 0);
|
||||
@@ -165,7 +164,8 @@ void rsa_disable(struct uart_8250_port *up)
|
||||
if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16)
|
||||
return;
|
||||
|
||||
uart_port_lock_irq(&up->port);
|
||||
guard(uart_port_lock_irq)(&up->port);
|
||||
|
||||
mode = serial_in(up, UART_RSA_MSR);
|
||||
result = !(mode & UART_RSA_MSR_FIFO);
|
||||
|
||||
@@ -177,7 +177,6 @@ void rsa_disable(struct uart_8250_port *up)
|
||||
|
||||
if (result)
|
||||
up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
|
||||
uart_port_unlock_irq(&up->port);
|
||||
}
|
||||
EXPORT_SYMBOL_FOR_MODULES(rsa_disable, "8250_base");
|
||||
|
||||
|
||||
@@ -782,7 +782,7 @@ config SERIAL_CPM
|
||||
depends on CPM2 || CPM1
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver supports the SCC and SMC serial ports on Motorola
|
||||
This driver supports the SCC and SMC serial ports on Motorola
|
||||
embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx)
|
||||
|
||||
config SERIAL_CPM_CONSOLE
|
||||
@@ -928,6 +928,14 @@ config SERIAL_QCOM_GENI_CONSOLE
|
||||
Serial console driver for Qualcomm Technologies Inc's GENI based
|
||||
QUP hardware.
|
||||
|
||||
config SERIAL_QCOM_GENI_UART_PORTS
|
||||
int "Maximum number of GENI UART ports"
|
||||
depends on SERIAL_QCOM_GENI
|
||||
default "8"
|
||||
help
|
||||
Set this to the maximum number of serial ports you want the driver
|
||||
to support.
|
||||
|
||||
config SERIAL_VT8500
|
||||
bool "VIA VT8500 on-chip serial port support"
|
||||
depends on ARCH_VT8500 || COMPILE_TEST
|
||||
@@ -1412,7 +1420,7 @@ config SERIAL_STM32
|
||||
|
||||
config SERIAL_STM32_CONSOLE
|
||||
bool "Support for console on STM32"
|
||||
depends on SERIAL_STM32=y
|
||||
depends on SERIAL_STM32
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
|
||||
|
||||
+147
-213
@@ -30,6 +30,7 @@
|
||||
#include <linux/console.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <asm/irq.h>
|
||||
@@ -50,8 +51,9 @@
|
||||
#define ZSDELAY_LONG() udelay(20)
|
||||
#define ZS_WSYNC(channel) do { } while (0)
|
||||
|
||||
#define NUM_IP22ZILOG 1
|
||||
#define NUM_CHANNELS (NUM_IP22ZILOG * 2)
|
||||
#define NUM_CHANNELS 2
|
||||
#define CHANNEL_B 0
|
||||
#define CHANNEL_A 1
|
||||
|
||||
#define ZS_CLOCK 3672000 /* Zilog input clock rate. */
|
||||
#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */
|
||||
@@ -62,9 +64,6 @@
|
||||
struct uart_ip22zilog_port {
|
||||
struct uart_port port;
|
||||
|
||||
/* IRQ servicing chain. */
|
||||
struct uart_ip22zilog_port *next;
|
||||
|
||||
/* Current values of Zilog write registers. */
|
||||
unsigned char curregs[NUM_ZSREGS];
|
||||
|
||||
@@ -72,7 +71,6 @@ struct uart_ip22zilog_port {
|
||||
#define IP22ZILOG_FLAG_IS_CONS 0x00000004
|
||||
#define IP22ZILOG_FLAG_IS_KGDB 0x00000008
|
||||
#define IP22ZILOG_FLAG_MODEM_STATUS 0x00000010
|
||||
#define IP22ZILOG_FLAG_IS_CHANNEL_A 0x00000020
|
||||
#define IP22ZILOG_FLAG_REGS_HELD 0x00000040
|
||||
#define IP22ZILOG_FLAG_TX_STOPPED 0x00000080
|
||||
#define IP22ZILOG_FLAG_TX_ACTIVE 0x00000100
|
||||
@@ -84,6 +82,8 @@ struct uart_ip22zilog_port {
|
||||
unsigned char prev_status;
|
||||
};
|
||||
|
||||
static struct uart_ip22zilog_port ip22zilog_port_table[NUM_CHANNELS];
|
||||
|
||||
#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel *)((PORT)->membase))
|
||||
#define UART_ZILOG(PORT) ((struct uart_ip22zilog_port *)(PORT))
|
||||
#define IP22ZILOG_GET_CURR_REG(PORT, REGNUM) \
|
||||
@@ -93,7 +93,6 @@ struct uart_ip22zilog_port {
|
||||
#define ZS_IS_CONS(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CONS)
|
||||
#define ZS_IS_KGDB(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_KGDB)
|
||||
#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS)
|
||||
#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A)
|
||||
#define ZS_REGS_HELD(UP) ((UP)->flags & IP22ZILOG_FLAG_REGS_HELD)
|
||||
#define ZS_TX_STOPPED(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED)
|
||||
#define ZS_TX_ACTIVE(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE)
|
||||
@@ -423,60 +422,57 @@ ack_tx_int:
|
||||
|
||||
static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_ip22zilog_port *up = dev_id;
|
||||
struct uart_ip22zilog_port *up;
|
||||
struct zilog_channel *channel;
|
||||
unsigned char r3;
|
||||
bool push = false;
|
||||
|
||||
while (up) {
|
||||
struct zilog_channel *channel
|
||||
= ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
unsigned char r3;
|
||||
bool push = false;
|
||||
up = &ip22zilog_port_table[CHANNEL_A];
|
||||
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
|
||||
uart_port_lock(&up->port);
|
||||
r3 = read_zsreg(channel, R3);
|
||||
uart_port_lock(&up->port);
|
||||
r3 = read_zsreg(channel, R3);
|
||||
|
||||
/* Channel A */
|
||||
if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
|
||||
writeb(RES_H_IUS, &channel->control);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
/* Channel A */
|
||||
if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
|
||||
writeb(RES_H_IUS, &channel->control);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
if (r3 & CHARxIP)
|
||||
push = ip22zilog_receive_chars(up, channel);
|
||||
if (r3 & CHAEXT)
|
||||
ip22zilog_status_handle(up, channel);
|
||||
if (r3 & CHATxIP)
|
||||
ip22zilog_transmit_chars(up, channel);
|
||||
}
|
||||
uart_port_unlock(&up->port);
|
||||
|
||||
if (push)
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
|
||||
/* Channel B */
|
||||
up = up->next;
|
||||
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
push = false;
|
||||
|
||||
uart_port_lock(&up->port);
|
||||
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
|
||||
writeb(RES_H_IUS, &channel->control);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
if (r3 & CHBRxIP)
|
||||
push = ip22zilog_receive_chars(up, channel);
|
||||
if (r3 & CHBEXT)
|
||||
ip22zilog_status_handle(up, channel);
|
||||
if (r3 & CHBTxIP)
|
||||
ip22zilog_transmit_chars(up, channel);
|
||||
}
|
||||
uart_port_unlock(&up->port);
|
||||
|
||||
if (push)
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
|
||||
up = up->next;
|
||||
if (r3 & CHARxIP)
|
||||
push = ip22zilog_receive_chars(up, channel);
|
||||
if (r3 & CHAEXT)
|
||||
ip22zilog_status_handle(up, channel);
|
||||
if (r3 & CHATxIP)
|
||||
ip22zilog_transmit_chars(up, channel);
|
||||
}
|
||||
uart_port_unlock(&up->port);
|
||||
|
||||
if (push)
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
|
||||
/* Channel B */
|
||||
up = &ip22zilog_port_table[CHANNEL_B];
|
||||
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
push = false;
|
||||
|
||||
uart_port_lock(&up->port);
|
||||
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
|
||||
writeb(RES_H_IUS, &channel->control);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
if (r3 & CHBRxIP)
|
||||
push = ip22zilog_receive_chars(up, channel);
|
||||
if (r3 & CHBEXT)
|
||||
ip22zilog_status_handle(up, channel);
|
||||
if (r3 & CHBTxIP)
|
||||
ip22zilog_transmit_chars(up, channel);
|
||||
}
|
||||
uart_port_unlock(&up->port);
|
||||
|
||||
if (push)
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -692,16 +688,16 @@ static void __ip22zilog_reset(struct uart_ip22zilog_port *up)
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (!ZS_IS_CHANNEL_A(up)) {
|
||||
up++;
|
||||
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
}
|
||||
up = &ip22zilog_port_table[CHANNEL_A];
|
||||
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
|
||||
write_zsreg(channel, R9, FHWRES);
|
||||
ZSDELAY_LONG();
|
||||
(void) read_zsreg(channel, R0);
|
||||
|
||||
up->flags |= IP22ZILOG_FLAG_RESET_DONE;
|
||||
up->next->flags |= IP22ZILOG_FLAG_RESET_DONE;
|
||||
up = &ip22zilog_port_table[CHANNEL_B];
|
||||
up->flags |= IP22ZILOG_FLAG_RESET_DONE;
|
||||
}
|
||||
|
||||
static void __ip22zilog_startup(struct uart_ip22zilog_port *up)
|
||||
@@ -942,47 +938,6 @@ static const struct uart_ops ip22zilog_pops = {
|
||||
.verify_port = ip22zilog_verify_port,
|
||||
};
|
||||
|
||||
static struct uart_ip22zilog_port *ip22zilog_port_table;
|
||||
static struct zilog_layout **ip22zilog_chip_regs;
|
||||
|
||||
static struct uart_ip22zilog_port *ip22zilog_irq_chain;
|
||||
static int zilog_irq = -1;
|
||||
|
||||
static void * __init alloc_one_table(unsigned long size)
|
||||
{
|
||||
return kzalloc(size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void __init ip22zilog_alloc_tables(void)
|
||||
{
|
||||
ip22zilog_port_table = (struct uart_ip22zilog_port *)
|
||||
alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port));
|
||||
ip22zilog_chip_regs = (struct zilog_layout **)
|
||||
alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *));
|
||||
|
||||
if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) {
|
||||
panic("IP22-Zilog: Cannot allocate IP22-Zilog tables.");
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the address of the registers for IP22-Zilog instance CHIP. */
|
||||
static struct zilog_layout * __init get_zs(int chip)
|
||||
{
|
||||
unsigned long base;
|
||||
|
||||
if (chip < 0 || chip >= NUM_IP22ZILOG) {
|
||||
panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip);
|
||||
}
|
||||
|
||||
/* Not probe-able, hard code it. */
|
||||
base = (unsigned long) &sgioc->uart;
|
||||
|
||||
zilog_irq = SGI_SERIAL_IRQ;
|
||||
request_mem_region(base, 8, "IP22-Zilog");
|
||||
|
||||
return (struct zilog_layout *) base;
|
||||
}
|
||||
|
||||
#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */
|
||||
|
||||
#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
|
||||
@@ -1070,144 +1025,123 @@ static struct uart_driver ip22zilog_reg = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static void __init ip22zilog_prepare(void)
|
||||
static void __init ip22zilog_prepare(struct uart_ip22zilog_port *up)
|
||||
{
|
||||
unsigned char sysrq_on = IS_ENABLED(CONFIG_SERIAL_IP22_ZILOG_CONSOLE);
|
||||
struct uart_ip22zilog_port *up;
|
||||
struct zilog_layout *rp;
|
||||
int channel, chip;
|
||||
int brg;
|
||||
|
||||
/*
|
||||
* Temporary fix.
|
||||
*/
|
||||
for (channel = 0; channel < NUM_CHANNELS; channel++)
|
||||
spin_lock_init(&ip22zilog_port_table[channel].port.lock);
|
||||
spin_lock_init(&up->port.lock);
|
||||
|
||||
ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1];
|
||||
up = &ip22zilog_port_table[0];
|
||||
for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--)
|
||||
up[channel].next = &up[channel - 1];
|
||||
up[channel].next = NULL;
|
||||
up->port.iotype = UPIO_MEM;
|
||||
up->port.uartclk = ZS_CLOCK;
|
||||
up->port.fifosize = 1;
|
||||
up->port.has_sysrq = sysrq_on;
|
||||
up->port.ops = &ip22zilog_pops;
|
||||
up->port.type = PORT_IP22ZILOG;
|
||||
|
||||
for (chip = 0; chip < NUM_IP22ZILOG; chip++) {
|
||||
if (!ip22zilog_chip_regs[chip]) {
|
||||
ip22zilog_chip_regs[chip] = rp = get_zs(chip);
|
||||
|
||||
up[(chip * 2) + 0].port.membase = (char *) &rp->channelB;
|
||||
up[(chip * 2) + 1].port.membase = (char *) &rp->channelA;
|
||||
|
||||
/* In theory mapbase is the physical address ... */
|
||||
up[(chip * 2) + 0].port.mapbase =
|
||||
(unsigned long) ioremap((unsigned long) &rp->channelB, 8);
|
||||
up[(chip * 2) + 1].port.mapbase =
|
||||
(unsigned long) ioremap((unsigned long) &rp->channelA, 8);
|
||||
}
|
||||
|
||||
/* Channel A */
|
||||
up[(chip * 2) + 0].port.iotype = UPIO_MEM;
|
||||
up[(chip * 2) + 0].port.irq = zilog_irq;
|
||||
up[(chip * 2) + 0].port.uartclk = ZS_CLOCK;
|
||||
up[(chip * 2) + 0].port.fifosize = 1;
|
||||
up[(chip * 2) + 0].port.has_sysrq = sysrq_on;
|
||||
up[(chip * 2) + 0].port.ops = &ip22zilog_pops;
|
||||
up[(chip * 2) + 0].port.type = PORT_IP22ZILOG;
|
||||
up[(chip * 2) + 0].port.flags = 0;
|
||||
up[(chip * 2) + 0].port.line = (chip * 2) + 0;
|
||||
up[(chip * 2) + 0].flags = 0;
|
||||
|
||||
/* Channel B */
|
||||
up[(chip * 2) + 1].port.iotype = UPIO_MEM;
|
||||
up[(chip * 2) + 1].port.irq = zilog_irq;
|
||||
up[(chip * 2) + 1].port.uartclk = ZS_CLOCK;
|
||||
up[(chip * 2) + 1].port.fifosize = 1;
|
||||
up[(chip * 2) + 1].port.has_sysrq = sysrq_on;
|
||||
up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
|
||||
up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
|
||||
up[(chip * 2) + 1].port.line = (chip * 2) + 1;
|
||||
up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
|
||||
}
|
||||
|
||||
for (channel = 0; channel < NUM_CHANNELS; channel++) {
|
||||
struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel];
|
||||
int brg;
|
||||
|
||||
/* Normal serial TTY. */
|
||||
up->parity_mask = 0xff;
|
||||
up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
|
||||
up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
|
||||
up->curregs[R3] = RxENAB | Rx8;
|
||||
up->curregs[R5] = TxENAB | Tx8;
|
||||
up->curregs[R9] = NV | MIE;
|
||||
up->curregs[R10] = NRZ;
|
||||
up->curregs[R11] = TCBR | RCBR;
|
||||
brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR);
|
||||
up->curregs[R12] = (brg & 0xff);
|
||||
up->curregs[R13] = (brg >> 8) & 0xff;
|
||||
up->curregs[R14] = BRENAB;
|
||||
}
|
||||
/* Normal serial TTY. */
|
||||
up->parity_mask = 0xff;
|
||||
up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
|
||||
up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
|
||||
up->curregs[R3] = RxENAB | Rx8;
|
||||
up->curregs[R5] = TxENAB | Tx8;
|
||||
up->curregs[R9] = NV | MIE;
|
||||
up->curregs[R10] = NRZ;
|
||||
up->curregs[R11] = TCBR | RCBR;
|
||||
brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR);
|
||||
up->curregs[R12] = (brg & 0xff);
|
||||
up->curregs[R13] = (brg >> 8) & 0xff;
|
||||
up->curregs[R14] = BRENAB;
|
||||
}
|
||||
|
||||
static int __init ip22zilog_ports_init(void)
|
||||
static int ip22zilog_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct uart_ip22zilog_port *up;
|
||||
char __iomem *membase;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int i;
|
||||
|
||||
printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG);
|
||||
up = &ip22zilog_port_table[CHANNEL_B];
|
||||
if (up->port.dev)
|
||||
return -ENOSPC;
|
||||
|
||||
ip22zilog_prepare();
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
if (request_irq(zilog_irq, ip22zilog_interrupt, 0,
|
||||
"IP22-Zilog", ip22zilog_irq_chain)) {
|
||||
membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(membase))
|
||||
return PTR_ERR(membase);
|
||||
|
||||
ip22zilog_prepare(up);
|
||||
|
||||
up->port.mapbase = res->start + offsetof(struct zilog_layout, channelB);
|
||||
up->port.membase = membase + offsetof(struct zilog_layout, channelB);
|
||||
up->port.line = 0;
|
||||
up->port.dev = &pdev->dev;
|
||||
up->port.irq = irq;
|
||||
|
||||
up = &ip22zilog_port_table[CHANNEL_A];
|
||||
ip22zilog_prepare(up);
|
||||
|
||||
up->port.mapbase = res->start + offsetof(struct zilog_layout, channelA);
|
||||
up->port.membase = membase + offsetof(struct zilog_layout, channelA);
|
||||
up->port.line = 1;
|
||||
up->port.dev = &pdev->dev;
|
||||
up->port.irq = irq;
|
||||
|
||||
if (request_irq(irq, ip22zilog_interrupt, 0,
|
||||
"IP22-Zilog", NULL)) {
|
||||
panic("IP22-Zilog: Unable to register zs interrupt handler.\n");
|
||||
}
|
||||
|
||||
ret = uart_register_driver(&ip22zilog_reg);
|
||||
if (ret == 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_CHANNELS; i++) {
|
||||
struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
|
||||
|
||||
uart_add_one_port(&ip22zilog_reg, &up->port);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init ip22zilog_init(void)
|
||||
{
|
||||
/* IP22 Zilog setup is hard coded, no probing to do. */
|
||||
ip22zilog_alloc_tables();
|
||||
ip22zilog_ports_init();
|
||||
for (i = 0; i < NUM_CHANNELS; i++)
|
||||
uart_add_one_port(&ip22zilog_reg,
|
||||
&ip22zilog_port_table[i].port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ip22zilog_exit(void)
|
||||
static void ip22zilog_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
struct uart_ip22zilog_port *up;
|
||||
|
||||
for (i = 0; i < NUM_CHANNELS; i++) {
|
||||
up = &ip22zilog_port_table[i];
|
||||
|
||||
uart_remove_one_port(&ip22zilog_reg, &up->port);
|
||||
uart_remove_one_port(&ip22zilog_reg,
|
||||
&ip22zilog_port_table[i].port);
|
||||
ip22zilog_port_table[i].port.dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free IO mem */
|
||||
up = &ip22zilog_port_table[0];
|
||||
for (i = 0; i < NUM_IP22ZILOG; i++) {
|
||||
if (up[(i * 2) + 0].port.mapbase) {
|
||||
iounmap((void*)up[(i * 2) + 0].port.mapbase);
|
||||
up[(i * 2) + 0].port.mapbase = 0;
|
||||
}
|
||||
if (up[(i * 2) + 1].port.mapbase) {
|
||||
iounmap((void*)up[(i * 2) + 1].port.mapbase);
|
||||
up[(i * 2) + 1].port.mapbase = 0;
|
||||
}
|
||||
static struct platform_driver ip22zilog_driver = {
|
||||
.probe = ip22zilog_probe,
|
||||
.remove = ip22zilog_remove,
|
||||
.driver = {
|
||||
.name = "ip22zilog"
|
||||
}
|
||||
};
|
||||
|
||||
static int __init ip22zilog_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uart_register_driver(&ip22zilog_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&ip22zilog_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&ip22zilog_reg);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static void __exit ip22zilog_exit(void)
|
||||
{
|
||||
uart_unregister_driver(&ip22zilog_reg);
|
||||
platform_driver_unregister(&ip22zilog_driver);
|
||||
}
|
||||
|
||||
module_init(ip22zilog_init);
|
||||
|
||||
@@ -705,7 +705,7 @@ static int max3100_probe(struct spi_device *spi)
|
||||
break;
|
||||
if (i == MAX_MAX3100) {
|
||||
mutex_unlock(&max3100s_lock);
|
||||
return dev_err_probe(dev, -ENOMEM, "too many MAX3100 chips\n");
|
||||
return dev_err_probe(dev, -ENOSPC, "too many MAX3100 chips\n");
|
||||
}
|
||||
|
||||
max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL);
|
||||
|
||||
@@ -823,17 +823,28 @@ static irqreturn_t max310x_ist(int irq, void *dev_id)
|
||||
bool handled = false;
|
||||
|
||||
if (s->devtype->nr > 1) {
|
||||
bool done;
|
||||
|
||||
do {
|
||||
unsigned int val = ~0;
|
||||
unsigned long irq;
|
||||
unsigned int port;
|
||||
|
||||
done = true;
|
||||
|
||||
WARN_ON_ONCE(regmap_read(s->regmap,
|
||||
MAX310X_GLOBALIRQ_REG, &val));
|
||||
val = ((1 << s->devtype->nr) - 1) & ~val;
|
||||
if (!val)
|
||||
break;
|
||||
if (max310x_port_irq(s, fls(val) - 1) == IRQ_HANDLED)
|
||||
handled = true;
|
||||
} while (1);
|
||||
|
||||
irq = val;
|
||||
|
||||
for_each_clear_bit(port, &irq, s->devtype->nr) {
|
||||
done = false;
|
||||
|
||||
if (max310x_port_irq(s, port) == IRQ_HANDLED)
|
||||
handled = true;
|
||||
}
|
||||
|
||||
} while (!done);
|
||||
} else {
|
||||
if (max310x_port_irq(s, 0) == IRQ_HANDLED)
|
||||
handled = true;
|
||||
@@ -1269,8 +1280,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
|
||||
/* Alloc port structure */
|
||||
s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL);
|
||||
if (!s)
|
||||
return dev_err_probe(dev, -ENOMEM,
|
||||
"Error allocating port structure\n");
|
||||
return -ENOMEM;
|
||||
|
||||
/* Always ask for fixed clock rate from a property. */
|
||||
device_property_read_u32(dev, "clock-frequency", &uartclk);
|
||||
@@ -1644,6 +1654,8 @@ static int max310x_i2c_probe(struct i2c_client *client)
|
||||
port_client = devm_i2c_new_dummy_device(&client->dev,
|
||||
client->adapter,
|
||||
port_addr);
|
||||
if (IS_ERR(port_client))
|
||||
return PTR_ERR(port_client);
|
||||
|
||||
regcfg_i2c.name = max310x_regmap_name(i);
|
||||
regmaps[i] = devm_regmap_init_i2c(port_client, ®cfg_i2c);
|
||||
|
||||
@@ -1102,7 +1102,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud,
|
||||
|
||||
if (result == baud)
|
||||
break;
|
||||
} else if (entry->divisor > divisor) {
|
||||
} else {
|
||||
old = target;
|
||||
target = clk_round_rate(msm_port->clk, old + 1);
|
||||
/*
|
||||
|
||||
@@ -1264,14 +1264,16 @@ static unsigned long mvebu_uart_clock_recalc_rate(struct clk_hw *hw,
|
||||
return parent_rate / uart_clock_base->div;
|
||||
}
|
||||
|
||||
static long mvebu_uart_clock_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int mvebu_uart_clock_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
|
||||
struct mvebu_uart_clock_base *uart_clock_base =
|
||||
to_uart_clock_base(uart_clock);
|
||||
|
||||
return *parent_rate / uart_clock_base->div;
|
||||
req->rate = req->best_parent_rate / uart_clock_base->div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_uart_clock_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -1293,7 +1295,7 @@ static const struct clk_ops mvebu_uart_clock_ops = {
|
||||
.is_enabled = mvebu_uart_clock_is_enabled,
|
||||
.save_context = mvebu_uart_clock_save_context,
|
||||
.restore_context = mvebu_uart_clock_restore_context,
|
||||
.round_rate = mvebu_uart_clock_round_rate,
|
||||
.determine_rate = mvebu_uart_clock_determine_rate,
|
||||
.set_rate = mvebu_uart_clock_set_rate,
|
||||
.recalc_rate = mvebu_uart_clock_recalc_rate,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
|
||||
/*
|
||||
* Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
/* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */
|
||||
#define __DISABLE_TRACE_MMIO__
|
||||
@@ -77,7 +80,6 @@
|
||||
#define STALE_TIMEOUT 16
|
||||
#define DEFAULT_BITS_PER_CHAR 10
|
||||
#define GENI_UART_CONS_PORTS 1
|
||||
#define GENI_UART_PORTS 3
|
||||
#define DEF_FIFO_DEPTH_WORDS 16
|
||||
#define DEF_TX_WM 2
|
||||
#define DEF_FIFO_WIDTH_BITS 32
|
||||
@@ -164,33 +166,6 @@ static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport)
|
||||
return container_of(uport, struct qcom_geni_serial_port, uport);
|
||||
}
|
||||
|
||||
static struct qcom_geni_serial_port qcom_geni_uart_ports[GENI_UART_PORTS] = {
|
||||
[0] = {
|
||||
.uport = {
|
||||
.iotype = UPIO_MEM,
|
||||
.ops = &qcom_geni_uart_pops,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 0,
|
||||
},
|
||||
},
|
||||
[1] = {
|
||||
.uport = {
|
||||
.iotype = UPIO_MEM,
|
||||
.ops = &qcom_geni_uart_pops,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 1,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
.uport = {
|
||||
.iotype = UPIO_MEM,
|
||||
.ops = &qcom_geni_uart_pops,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 2,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct qcom_geni_serial_port qcom_geni_console_port = {
|
||||
.uport = {
|
||||
.iotype = UPIO_MEM,
|
||||
@@ -285,10 +260,10 @@ static const char *qcom_geni_serial_get_type(struct uart_port *uport)
|
||||
return "MSM";
|
||||
}
|
||||
|
||||
static struct qcom_geni_serial_port *get_port_from_line(int line, bool console)
|
||||
static struct qcom_geni_serial_port *get_port_from_line(int line, bool console, struct device *dev)
|
||||
{
|
||||
struct qcom_geni_serial_port *port;
|
||||
int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS;
|
||||
int nr_ports = console ? GENI_UART_CONS_PORTS : CONFIG_SERIAL_QCOM_GENI_UART_PORTS;
|
||||
|
||||
if (console) {
|
||||
if (line < 0 || line >= nr_ports)
|
||||
@@ -299,14 +274,23 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console)
|
||||
int max_alias_num = of_alias_get_highest_id("serial");
|
||||
|
||||
if (line < 0 || line >= nr_ports)
|
||||
line = ida_alloc_range(&port_ida, max_alias_num + 1, nr_ports, GFP_KERNEL);
|
||||
line = ida_alloc_range(&port_ida, max_alias_num + 1,
|
||||
nr_ports - 1, GFP_KERNEL);
|
||||
else
|
||||
line = ida_alloc_range(&port_ida, line, nr_ports, GFP_KERNEL);
|
||||
line = ida_alloc_range(&port_ida, line,
|
||||
nr_ports - 1, GFP_KERNEL);
|
||||
|
||||
if (line < 0)
|
||||
return ERR_PTR(-ENXIO);
|
||||
|
||||
port = &qcom_geni_uart_ports[line];
|
||||
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
|
||||
if (!port)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
port->uport.iotype = UPIO_MEM;
|
||||
port->uport.ops = &qcom_geni_uart_pops;
|
||||
port->uport.flags = UPF_BOOT_AUTOCONF;
|
||||
port->uport.line = line;
|
||||
}
|
||||
return port;
|
||||
}
|
||||
@@ -554,7 +538,7 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
|
||||
|
||||
WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
|
||||
|
||||
port = get_port_from_line(co->index, true);
|
||||
port = get_port_from_line(co->index, true, NULL);
|
||||
if (IS_ERR(port))
|
||||
return;
|
||||
|
||||
@@ -1267,75 +1251,15 @@ static int qcom_geni_serial_startup(struct uart_port *uport)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long find_clk_rate_in_tol(struct clk *clk, unsigned int desired_clk,
|
||||
unsigned int *clk_div, unsigned int percent_tol)
|
||||
{
|
||||
unsigned long freq;
|
||||
unsigned long div, maxdiv;
|
||||
u64 mult;
|
||||
unsigned long offset, abs_tol, achieved;
|
||||
|
||||
abs_tol = div_u64((u64)desired_clk * percent_tol, 100);
|
||||
maxdiv = CLK_DIV_MSK >> CLK_DIV_SHFT;
|
||||
div = 1;
|
||||
while (div <= maxdiv) {
|
||||
mult = (u64)div * desired_clk;
|
||||
if (mult != (unsigned long)mult)
|
||||
break;
|
||||
|
||||
offset = div * abs_tol;
|
||||
freq = clk_round_rate(clk, mult - offset);
|
||||
|
||||
/* Can only get lower if we're done */
|
||||
if (freq < mult - offset)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Re-calculate div in case rounding skipped rates but we
|
||||
* ended up at a good one, then check for a match.
|
||||
*/
|
||||
div = DIV_ROUND_CLOSEST(freq, desired_clk);
|
||||
achieved = DIV_ROUND_CLOSEST(freq, div);
|
||||
if (achieved <= desired_clk + abs_tol &&
|
||||
achieved >= desired_clk - abs_tol) {
|
||||
*clk_div = div;
|
||||
return freq;
|
||||
}
|
||||
|
||||
div = DIV_ROUND_UP(freq, desired_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud,
|
||||
unsigned int sampling_rate, unsigned int *clk_div)
|
||||
{
|
||||
unsigned long ser_clk;
|
||||
unsigned long desired_clk;
|
||||
|
||||
desired_clk = baud * sampling_rate;
|
||||
if (!desired_clk)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* try to find a clock rate within 2% tolerance, then within 5%
|
||||
*/
|
||||
ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 2);
|
||||
if (!ser_clk)
|
||||
ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 5);
|
||||
|
||||
return ser_clk;
|
||||
}
|
||||
|
||||
static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
unsigned long clk_rate;
|
||||
unsigned int avg_bw_core;
|
||||
unsigned int avg_bw_core, clk_idx;
|
||||
unsigned int clk_div;
|
||||
u32 ver, sampling_rate;
|
||||
u32 ser_clk_cfg;
|
||||
int ret;
|
||||
|
||||
sampling_rate = UART_OVERSAMPLING;
|
||||
/* Sampling rate is halved for IP versions >= 2.5 */
|
||||
@@ -1343,17 +1267,22 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
|
||||
if (ver >= QUP_SE_VERSION_2_5)
|
||||
sampling_rate /= 2;
|
||||
|
||||
clk_rate = get_clk_div_rate(port->se.clk, baud,
|
||||
sampling_rate, &clk_div);
|
||||
if (!clk_rate) {
|
||||
dev_err(port->se.dev,
|
||||
"Couldn't find suitable clock rate for %u\n",
|
||||
baud * sampling_rate);
|
||||
ret = geni_se_clk_freq_match(&port->se, baud * sampling_rate, &clk_idx, &clk_rate, false);
|
||||
if (ret) {
|
||||
dev_err(port->se.dev, "Failed to find src clk for baud rate: %d ret: %d\n",
|
||||
baud, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_div = DIV_ROUND_UP(clk_rate, baud * sampling_rate);
|
||||
/* Check if calculated divider exceeds maximum allowed value */
|
||||
if (clk_div > (CLK_DIV_MSK >> CLK_DIV_SHFT)) {
|
||||
dev_err(port->se.dev, "Calculated clock divider %u exceeds maximum\n", clk_div);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n",
|
||||
baud * sampling_rate, clk_rate, clk_div);
|
||||
dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n, clk_idx = %u\n",
|
||||
baud * sampling_rate, clk_rate, clk_div, clk_idx);
|
||||
|
||||
uport->uartclk = clk_rate;
|
||||
port->clk_rate = clk_rate;
|
||||
@@ -1373,6 +1302,8 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
|
||||
|
||||
writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
|
||||
writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
|
||||
/* Configure clock selection register with the selected clock index */
|
||||
writel(clk_idx & CLK_SEL_MSK, uport->membase + SE_GENI_CLK_SEL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1517,7 +1448,7 @@ static int qcom_geni_console_setup(struct console *co, char *options)
|
||||
if (co->index >= GENI_UART_CONS_PORTS || co->index < 0)
|
||||
return -ENXIO;
|
||||
|
||||
port = get_port_from_line(co->index, true);
|
||||
port = get_port_from_line(co->index, true, NULL);
|
||||
if (IS_ERR(port)) {
|
||||
pr_err("Invalid line %d\n", co->index);
|
||||
return PTR_ERR(port);
|
||||
@@ -1678,7 +1609,7 @@ static struct uart_driver qcom_geni_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "qcom_geni_uart",
|
||||
.dev_name = "ttyHS",
|
||||
.nr = GENI_UART_PORTS,
|
||||
.nr = CONFIG_SERIAL_QCOM_GENI_UART_PORTS,
|
||||
};
|
||||
|
||||
static int geni_serial_resources_on(struct uart_port *uport)
|
||||
@@ -1872,7 +1803,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
||||
line = of_alias_get_id(pdev->dev.of_node, "hsuart");
|
||||
}
|
||||
|
||||
port = get_port_from_line(line, data->console);
|
||||
port = get_port_from_line(line, data->console, &pdev->dev);
|
||||
if (IS_ERR(port)) {
|
||||
dev_err(&pdev->dev, "Invalid line %d\n", line);
|
||||
return PTR_ERR(port);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user