Lines Matching +full:sun4i +full:- +full:a10 +full:- +full:ps2

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Driver for Allwinner A10 PS2 host controller
19 #define DRIVER_NAME "sun4i-ps2"
22 #define PS2_REG_GCTL 0x00 /* PS2 Module Global Control Reg */
23 #define PS2_REG_DATA 0x04 /* PS2 Module Data Reg */
24 #define PS2_REG_LCTL 0x08 /* PS2 Module Line Control Reg */
25 #define PS2_REG_LSTS 0x0C /* PS2 Module Line Status Reg */
26 #define PS2_REG_FCTL 0x10 /* PS2 Module FIFO Control Reg */
27 #define PS2_REG_FSTS 0x14 /* PS2 Module FIFO Status Reg */
28 #define PS2_REG_CLKDR 0x18 /* PS2 Module Clock Divider Reg*/
30 /* PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
37 /* PS2 LINE CONTROL REGISTER */
45 /* PS2 LINE STATUS REGISTER */
56 /* PS2 FIFO CONTROL REGISTER */
66 /* PS2 FIFO STATUS REGISTER */
104 spin_lock(&drvdata->lock); in sun4i_ps2_interrupt()
107 intr_status = readl(drvdata->reg_base + PS2_REG_LSTS); in sun4i_ps2_interrupt()
108 fifo_status = readl(drvdata->reg_base + PS2_REG_FSTS); in sun4i_ps2_interrupt()
118 writel(rval, drvdata->reg_base + PS2_REG_LSTS); in sun4i_ps2_interrupt()
125 writel(rval, drvdata->reg_base + PS2_REG_FSTS); in sun4i_ps2_interrupt()
129 while (rval--) { in sun4i_ps2_interrupt()
130 byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff; in sun4i_ps2_interrupt()
131 serio_interrupt(drvdata->serio, byte, rxflags); in sun4i_ps2_interrupt()
134 writel(intr_status, drvdata->reg_base + PS2_REG_LSTS); in sun4i_ps2_interrupt()
135 writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS); in sun4i_ps2_interrupt()
137 spin_unlock(&drvdata->lock); in sun4i_ps2_interrupt()
144 struct sun4i_ps2data *drvdata = serio->port_data; in sun4i_ps2_open()
154 writel(rval, drvdata->reg_base + PS2_REG_LCTL); in sun4i_ps2_open()
161 writel(rval, drvdata->reg_base + PS2_REG_FCTL); in sun4i_ps2_open()
163 src_clk = clk_get_rate(drvdata->clk); in sun4i_ps2_open()
165 clk_scdf = src_clk / PS2_SAMPLE_CLK - 1; in sun4i_ps2_open()
166 clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1; in sun4i_ps2_open()
168 writel(rval, drvdata->reg_base + PS2_REG_CLKDR); in sun4i_ps2_open()
174 spin_lock_irqsave(&drvdata->lock, flags); in sun4i_ps2_open()
175 writel(rval, drvdata->reg_base + PS2_REG_GCTL); in sun4i_ps2_open()
176 spin_unlock_irqrestore(&drvdata->lock, flags); in sun4i_ps2_open()
183 struct sun4i_ps2data *drvdata = serio->port_data; in sun4i_ps2_close()
187 rval = readl(drvdata->reg_base + PS2_REG_GCTL); in sun4i_ps2_close()
188 writel(rval & ~(PS2_GCTL_INTEN), drvdata->reg_base + PS2_REG_GCTL); in sun4i_ps2_close()
190 synchronize_irq(drvdata->irq); in sun4i_ps2_close()
196 struct sun4i_ps2data *drvdata = serio->port_data; in sun4i_ps2_write()
199 if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) { in sun4i_ps2_write()
200 writel(val, drvdata->reg_base + PS2_REG_DATA); in sun4i_ps2_write()
213 struct device *dev = &pdev->dev; in sun4i_ps2_probe()
219 error = -ENOMEM; in sun4i_ps2_probe()
223 spin_lock_init(&drvdata->lock); in sun4i_ps2_probe()
229 error = -ENXIO; in sun4i_ps2_probe()
233 drvdata->reg_base = ioremap(res->start, resource_size(res)); in sun4i_ps2_probe()
234 if (!drvdata->reg_base) { in sun4i_ps2_probe()
236 error = -ENOMEM; in sun4i_ps2_probe()
240 drvdata->clk = clk_get(dev, NULL); in sun4i_ps2_probe()
241 if (IS_ERR(drvdata->clk)) { in sun4i_ps2_probe()
242 error = PTR_ERR(drvdata->clk); in sun4i_ps2_probe()
247 error = clk_prepare_enable(drvdata->clk); in sun4i_ps2_probe()
253 serio->id.type = SERIO_8042; in sun4i_ps2_probe()
254 serio->write = sun4i_ps2_write; in sun4i_ps2_probe()
255 serio->open = sun4i_ps2_open; in sun4i_ps2_probe()
256 serio->close = sun4i_ps2_close; in sun4i_ps2_probe()
257 serio->port_data = drvdata; in sun4i_ps2_probe()
258 serio->dev.parent = dev; in sun4i_ps2_probe()
259 strscpy(serio->name, dev_name(dev), sizeof(serio->name)); in sun4i_ps2_probe()
260 strscpy(serio->phys, dev_name(dev), sizeof(serio->phys)); in sun4i_ps2_probe()
263 writel(0, drvdata->reg_base + PS2_REG_GCTL); in sun4i_ps2_probe()
266 drvdata->irq = platform_get_irq(pdev, 0); in sun4i_ps2_probe()
267 if (drvdata->irq < 0) { in sun4i_ps2_probe()
268 error = drvdata->irq; in sun4i_ps2_probe()
272 drvdata->serio = serio; in sun4i_ps2_probe()
273 drvdata->dev = dev; in sun4i_ps2_probe()
275 error = request_irq(drvdata->irq, sun4i_ps2_interrupt, 0, in sun4i_ps2_probe()
278 dev_err(drvdata->dev, "failed to allocate interrupt %d: %d\n", in sun4i_ps2_probe()
279 drvdata->irq, error); in sun4i_ps2_probe()
289 clk_disable_unprepare(drvdata->clk); in sun4i_ps2_probe()
291 clk_put(drvdata->clk); in sun4i_ps2_probe()
293 iounmap(drvdata->reg_base); in sun4i_ps2_probe()
304 serio_unregister_port(drvdata->serio); in sun4i_ps2_remove()
306 free_irq(drvdata->irq, drvdata); in sun4i_ps2_remove()
308 clk_disable_unprepare(drvdata->clk); in sun4i_ps2_remove()
309 clk_put(drvdata->clk); in sun4i_ps2_remove()
311 iounmap(drvdata->reg_base); in sun4i_ps2_remove()
319 { .compatible = "allwinner,sun4i-a10-ps2", },
337 MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");