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  
26  struct 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  
amba_kmi_int(int irq,void * dev_id)35  static 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  
amba_kmi_write(struct serio * io,unsigned char val)50  static 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  
amba_kmi_open(struct serio * io)64  static 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  
amba_kmi_close(struct serio * io)96  static 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  
amba_kmi_probe(struct amba_device * dev,const struct amba_id * id)106  static 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(*kmi), GFP_KERNEL);
118  	io = kzalloc(sizeof(*io), 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  	strscpy(io->name, dev_name(&dev->dev), sizeof(io->name));
130  	strscpy(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  
amba_kmi_remove(struct amba_device * dev)162  static 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  
amba_kmi_resume(struct device * dev)173  static int 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  
183  static DEFINE_SIMPLE_DEV_PM_OPS(amba_kmi_dev_pm_ops, NULL, amba_kmi_resume);
184  
185  static const struct amba_id amba_kmi_idtable[] = {
186  	{
187  		.id	= 0x00041050,
188  		.mask	= 0x000fffff,
189  	},
190  	{ 0, 0 }
191  };
192  
193  MODULE_DEVICE_TABLE(amba, amba_kmi_idtable);
194  
195  static struct amba_driver ambakmi_driver = {
196  	.drv		= {
197  		.name	= "kmi-pl050",
198  		.pm	= pm_sleep_ptr(&amba_kmi_dev_pm_ops),
199  	},
200  	.id_table	= amba_kmi_idtable,
201  	.probe		= amba_kmi_probe,
202  	.remove		= amba_kmi_remove,
203  };
204  
205  module_amba_driver(ambakmi_driver);
206  
207  MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
208  MODULE_DESCRIPTION("AMBA KMI controller driver");
209  MODULE_LICENSE("GPL");
210