2 * OLPC serio driver for multiplexed input from Marvell MMP security processor
4 * Copyright (C) 2011-2013 One Laptop Per Child
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include <linux/module.h>
18 #include <linux/interrupt.h>
19 #include <linux/serio.h>
20 #include <linux/err.h>
21 #include <linux/platform_device.h>
24 #include <linux/slab.h>
25 #include <linux/delay.h>
28 * The OLPC XO-1.75 and XO-4 laptops do not have a hardware PS/2 controller.
29 * Instead, the OLPC firmware runs a bit-banging PS/2 implementation on an
30 * otherwise-unused slow processor which is included in the Marvell MMP2/MMP3
31 * SoC, known as the "Security Processor" (SP) or "Wireless Trusted Module"
32 * (WTM). This firmware then reports its results via the WTM registers,
33 * which we read from the Application Processor (AP, i.e. main CPU) in this
36 * On the hardware side we have a PS/2 mouse and an AT keyboard, the data
37 * is multiplexed through this system. We create a serio port for each one,
38 * and demultiplex the data accordingly.
41 /* WTM register offsets */
42 #define SECURE_PROCESSOR_COMMAND 0x40
43 #define COMMAND_RETURN_STATUS 0x80
44 #define COMMAND_FIFO_STATUS 0xc4
45 #define PJ_RST_INTERRUPT 0xc8
46 #define PJ_INTERRUPT_MASK 0xcc
49 * The upper byte of SECURE_PROCESSOR_COMMAND and COMMAND_RETURN_STATUS is
50 * used to identify which port (device) is being talked to. The lower byte
51 * is the data being sent/received.
53 #define PORT_MASK 0xff00
54 #define DATA_MASK 0x00ff
56 #define KEYBOARD_PORT 0
57 #define TOUCHPAD_PORT 1
59 /* COMMAND_FIFO_STATUS */
60 #define CMD_CNTR_MASK 0x7 /* Number of pending/unprocessed commands */
61 #define MAX_PENDING_CMDS 4 /* from device specs */
63 /* PJ_RST_INTERRUPT */
64 #define SP_COMMAND_COMPLETE_RESET 0x1
66 /* PJ_INTERRUPT_MASK */
67 #define INT_0 (1 << 0)
69 /* COMMAND_FIFO_STATUS */
70 #define CMD_STS_MASK 0x100
81 static int olpc_apsp_write(struct serio
*port
, unsigned char val
)
83 struct olpc_apsp
*priv
= port
->port_data
;
87 if (port
== priv
->padio
)
88 which
= TOUCHPAD_PORT
<< PORT_SHIFT
;
90 which
= KEYBOARD_PORT
<< PORT_SHIFT
;
92 dev_dbg(priv
->dev
, "olpc_apsp_write which=%x val=%x\n", which
, val
);
93 for (i
= 0; i
< 50; i
++) {
94 u32 sts
= readl(priv
->base
+ COMMAND_FIFO_STATUS
);
95 if ((sts
& CMD_CNTR_MASK
) < MAX_PENDING_CMDS
) {
97 priv
->base
+ SECURE_PROCESSOR_COMMAND
);
100 /* SP busy. This has not been seen in practice. */
104 dev_dbg(priv
->dev
, "olpc_apsp_write timeout, status=%x\n",
105 readl(priv
->base
+ COMMAND_FIFO_STATUS
));
110 static irqreturn_t
olpc_apsp_rx(int irq
, void *dev_id
)
112 struct olpc_apsp
*priv
= dev_id
;
117 * Write 1 to PJ_RST_INTERRUPT to acknowledge and clear the interrupt
118 * Write 0xff00 to SECURE_PROCESSOR_COMMAND.
120 tmp
= readl(priv
->base
+ PJ_RST_INTERRUPT
);
121 if (!(tmp
& SP_COMMAND_COMPLETE_RESET
)) {
122 dev_warn(priv
->dev
, "spurious interrupt?\n");
126 w
= readl(priv
->base
+ COMMAND_RETURN_STATUS
);
127 dev_dbg(priv
->dev
, "olpc_apsp_rx %x\n", w
);
129 if (w
>> PORT_SHIFT
== KEYBOARD_PORT
)
134 serio_interrupt(serio
, w
& DATA_MASK
, 0);
136 /* Ack and clear interrupt */
137 writel(tmp
| SP_COMMAND_COMPLETE_RESET
, priv
->base
+ PJ_RST_INTERRUPT
);
138 writel(PORT_MASK
, priv
->base
+ SECURE_PROCESSOR_COMMAND
);
140 pm_wakeup_event(priv
->dev
, 1000);
144 static int olpc_apsp_open(struct serio
*port
)
146 struct olpc_apsp
*priv
= port
->port_data
;
149 if (priv
->open_count
++ == 0) {
150 /* Enable interrupt 0 by clearing its bit */
151 tmp
= readl(priv
->base
+ PJ_INTERRUPT_MASK
);
152 writel(tmp
& ~INT_0
, priv
->base
+ PJ_INTERRUPT_MASK
);
158 static void olpc_apsp_close(struct serio
*port
)
160 struct olpc_apsp
*priv
= port
->port_data
;
163 if (--priv
->open_count
== 0) {
164 /* Disable interrupt 0 */
165 tmp
= readl(priv
->base
+ PJ_INTERRUPT_MASK
);
166 writel(tmp
| INT_0
, priv
->base
+ PJ_INTERRUPT_MASK
);
170 static int olpc_apsp_probe(struct platform_device
*pdev
)
172 struct serio
*kb_serio
, *pad_serio
;
173 struct olpc_apsp
*priv
;
174 struct resource
*res
;
175 struct device_node
*np
;
179 priv
= devm_kzalloc(&pdev
->dev
, sizeof(struct olpc_apsp
), GFP_KERNEL
);
183 np
= pdev
->dev
.of_node
;
184 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
185 priv
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
186 if (IS_ERR(priv
->base
)) {
187 dev_err(&pdev
->dev
, "Failed to map WTM registers\n");
188 return PTR_ERR(priv
->base
);
191 priv
->irq
= platform_get_irq(pdev
, 0);
195 l
= readl(priv
->base
+ COMMAND_FIFO_STATUS
);
196 if (!(l
& CMD_STS_MASK
)) {
197 dev_err(&pdev
->dev
, "SP cannot accept commands.\n");
202 kb_serio
= kzalloc(sizeof(struct serio
), GFP_KERNEL
);
205 kb_serio
->id
.type
= SERIO_8042_XL
;
206 kb_serio
->write
= olpc_apsp_write
;
207 kb_serio
->open
= olpc_apsp_open
;
208 kb_serio
->close
= olpc_apsp_close
;
209 kb_serio
->port_data
= priv
;
210 kb_serio
->dev
.parent
= &pdev
->dev
;
211 strlcpy(kb_serio
->name
, "sp keyboard", sizeof(kb_serio
->name
));
212 strlcpy(kb_serio
->phys
, "sp/serio0", sizeof(kb_serio
->phys
));
213 priv
->kbio
= kb_serio
;
214 serio_register_port(kb_serio
);
217 pad_serio
= kzalloc(sizeof(struct serio
), GFP_KERNEL
);
222 pad_serio
->id
.type
= SERIO_8042
;
223 pad_serio
->write
= olpc_apsp_write
;
224 pad_serio
->open
= olpc_apsp_open
;
225 pad_serio
->close
= olpc_apsp_close
;
226 pad_serio
->port_data
= priv
;
227 pad_serio
->dev
.parent
= &pdev
->dev
;
228 strlcpy(pad_serio
->name
, "sp touchpad", sizeof(pad_serio
->name
));
229 strlcpy(pad_serio
->phys
, "sp/serio1", sizeof(pad_serio
->phys
));
230 priv
->padio
= pad_serio
;
231 serio_register_port(pad_serio
);
233 error
= request_irq(priv
->irq
, olpc_apsp_rx
, 0, "olpc-apsp", priv
);
235 dev_err(&pdev
->dev
, "Failed to request IRQ\n");
239 priv
->dev
= &pdev
->dev
;
240 device_init_wakeup(priv
->dev
, 1);
241 platform_set_drvdata(pdev
, priv
);
243 dev_dbg(&pdev
->dev
, "probed successfully.\n");
247 serio_unregister_port(pad_serio
);
249 serio_unregister_port(kb_serio
);
253 static int olpc_apsp_remove(struct platform_device
*pdev
)
255 struct olpc_apsp
*priv
= platform_get_drvdata(pdev
);
257 free_irq(priv
->irq
, priv
);
259 serio_unregister_port(priv
->kbio
);
260 serio_unregister_port(priv
->padio
);
265 static struct of_device_id olpc_apsp_dt_ids
[] = {
266 { .compatible
= "olpc,ap-sp", },
269 MODULE_DEVICE_TABLE(of
, olpc_apsp_dt_ids
);
271 static struct platform_driver olpc_apsp_driver
= {
272 .probe
= olpc_apsp_probe
,
273 .remove
= olpc_apsp_remove
,
276 .owner
= THIS_MODULE
,
277 .of_match_table
= olpc_apsp_dt_ids
,
281 MODULE_DESCRIPTION("OLPC AP-SP serio driver");
282 MODULE_LICENSE("GPL");
283 module_platform_driver(olpc_apsp_driver
);