cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ambakmi.c (4290B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  linux/drivers/input/serio/ambakmi.c
      4 *
      5 *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd.
      6 *  Copyright (C) 2002 Russell King.
      7 */
      8#include <linux/module.h>
      9#include <linux/serio.h>
     10#include <linux/errno.h>
     11#include <linux/interrupt.h>
     12#include <linux/ioport.h>
     13#include <linux/device.h>
     14#include <linux/delay.h>
     15#include <linux/slab.h>
     16#include <linux/err.h>
     17#include <linux/amba/bus.h>
     18#include <linux/amba/kmi.h>
     19#include <linux/clk.h>
     20
     21#include <asm/io.h>
     22#include <asm/irq.h>
     23
     24#define KMI_BASE	(kmi->base)
     25
     26struct amba_kmi_port {
     27	struct serio		*io;
     28	struct clk		*clk;
     29	void __iomem		*base;
     30	unsigned int		irq;
     31	unsigned int		divisor;
     32	unsigned int		open;
     33};
     34
     35static irqreturn_t amba_kmi_int(int irq, void *dev_id)
     36{
     37	struct amba_kmi_port *kmi = dev_id;
     38	unsigned int status = readb(KMIIR);
     39	int handled = IRQ_NONE;
     40
     41	while (status & KMIIR_RXINTR) {
     42		serio_interrupt(kmi->io, readb(KMIDATA), 0);
     43		status = readb(KMIIR);
     44		handled = IRQ_HANDLED;
     45	}
     46
     47	return handled;
     48}
     49
     50static int amba_kmi_write(struct serio *io, unsigned char val)
     51{
     52	struct amba_kmi_port *kmi = io->port_data;
     53	unsigned int timeleft = 10000; /* timeout in 100ms */
     54
     55	while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && --timeleft)
     56		udelay(10);
     57
     58	if (timeleft)
     59		writeb(val, KMIDATA);
     60
     61	return timeleft ? 0 : SERIO_TIMEOUT;
     62}
     63
     64static int amba_kmi_open(struct serio *io)
     65{
     66	struct amba_kmi_port *kmi = io->port_data;
     67	unsigned int divisor;
     68	int ret;
     69
     70	ret = clk_prepare_enable(kmi->clk);
     71	if (ret)
     72		goto out;
     73
     74	divisor = clk_get_rate(kmi->clk) / 8000000 - 1;
     75	writeb(divisor, KMICLKDIV);
     76	writeb(KMICR_EN, KMICR);
     77
     78	ret = request_irq(kmi->irq, amba_kmi_int, IRQF_SHARED, "kmi-pl050",
     79			  kmi);
     80	if (ret) {
     81		printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq);
     82		writeb(0, KMICR);
     83		goto clk_disable;
     84	}
     85
     86	writeb(KMICR_EN | KMICR_RXINTREN, KMICR);
     87
     88	return 0;
     89
     90 clk_disable:
     91	clk_disable_unprepare(kmi->clk);
     92 out:
     93	return ret;
     94}
     95
     96static void amba_kmi_close(struct serio *io)
     97{
     98	struct amba_kmi_port *kmi = io->port_data;
     99
    100	writeb(0, KMICR);
    101
    102	free_irq(kmi->irq, kmi);
    103	clk_disable_unprepare(kmi->clk);
    104}
    105
    106static int amba_kmi_probe(struct amba_device *dev,
    107	const struct amba_id *id)
    108{
    109	struct amba_kmi_port *kmi;
    110	struct serio *io;
    111	int ret;
    112
    113	ret = amba_request_regions(dev, NULL);
    114	if (ret)
    115		return ret;
    116
    117	kmi = kzalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
    118	io = kzalloc(sizeof(struct serio), GFP_KERNEL);
    119	if (!kmi || !io) {
    120		ret = -ENOMEM;
    121		goto out;
    122	}
    123
    124
    125	io->id.type	= SERIO_8042;
    126	io->write	= amba_kmi_write;
    127	io->open	= amba_kmi_open;
    128	io->close	= amba_kmi_close;
    129	strlcpy(io->name, dev_name(&dev->dev), sizeof(io->name));
    130	strlcpy(io->phys, dev_name(&dev->dev), sizeof(io->phys));
    131	io->port_data	= kmi;
    132	io->dev.parent	= &dev->dev;
    133
    134	kmi->io		= io;
    135	kmi->base	= ioremap(dev->res.start, resource_size(&dev->res));
    136	if (!kmi->base) {
    137		ret = -ENOMEM;
    138		goto out;
    139	}
    140
    141	kmi->clk = clk_get(&dev->dev, "KMIREFCLK");
    142	if (IS_ERR(kmi->clk)) {
    143		ret = PTR_ERR(kmi->clk);
    144		goto unmap;
    145	}
    146
    147	kmi->irq = dev->irq[0];
    148	amba_set_drvdata(dev, kmi);
    149
    150	serio_register_port(kmi->io);
    151	return 0;
    152
    153 unmap:
    154	iounmap(kmi->base);
    155 out:
    156	kfree(kmi);
    157	kfree(io);
    158	amba_release_regions(dev);
    159	return ret;
    160}
    161
    162static void amba_kmi_remove(struct amba_device *dev)
    163{
    164	struct amba_kmi_port *kmi = amba_get_drvdata(dev);
    165
    166	serio_unregister_port(kmi->io);
    167	clk_put(kmi->clk);
    168	iounmap(kmi->base);
    169	kfree(kmi);
    170	amba_release_regions(dev);
    171}
    172
    173static int __maybe_unused amba_kmi_resume(struct device *dev)
    174{
    175	struct amba_kmi_port *kmi = dev_get_drvdata(dev);
    176
    177	/* kick the serio layer to rescan this port */
    178	serio_reconnect(kmi->io);
    179
    180	return 0;
    181}
    182
    183static SIMPLE_DEV_PM_OPS(amba_kmi_dev_pm_ops, NULL, amba_kmi_resume);
    184
    185static const struct amba_id amba_kmi_idtable[] = {
    186	{
    187		.id	= 0x00041050,
    188		.mask	= 0x000fffff,
    189	},
    190	{ 0, 0 }
    191};
    192
    193MODULE_DEVICE_TABLE(amba, amba_kmi_idtable);
    194
    195static struct amba_driver ambakmi_driver = {
    196	.drv		= {
    197		.name	= "kmi-pl050",
    198		.owner	= THIS_MODULE,
    199		.pm	= &amba_kmi_dev_pm_ops,
    200	},
    201	.id_table	= amba_kmi_idtable,
    202	.probe		= amba_kmi_probe,
    203	.remove		= amba_kmi_remove,
    204};
    205
    206module_amba_driver(ambakmi_driver);
    207
    208MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
    209MODULE_DESCRIPTION("AMBA KMI controller driver");
    210MODULE_LICENSE("GPL");