diff options
| -rw-r--r-- | drivers/input/serio/xilinx_ps2.c | 220 |
1 files changed, 113 insertions, 107 deletions
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 765007899d9a..ebb22f88c842 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c | |||
| @@ -58,23 +58,20 @@ | |||
| 58 | 58 | ||
| 59 | /* Mask for all the Receive Interrupts */ | 59 | /* Mask for all the Receive Interrupts */ |
| 60 | #define XPS2_IPIXR_RX_ALL (XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR | \ | 60 | #define XPS2_IPIXR_RX_ALL (XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR | \ |
| 61 | XPS2_IPIXR_RX_FULL) | 61 | XPS2_IPIXR_RX_FULL) |
| 62 | 62 | ||
| 63 | /* Mask for all the Interrupts */ | 63 | /* Mask for all the Interrupts */ |
| 64 | #define XPS2_IPIXR_ALL (XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL | \ | 64 | #define XPS2_IPIXR_ALL (XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL | \ |
| 65 | XPS2_IPIXR_WDT_TOUT) | 65 | XPS2_IPIXR_WDT_TOUT) |
| 66 | 66 | ||
| 67 | /* Global Interrupt Enable mask */ | 67 | /* Global Interrupt Enable mask */ |
| 68 | #define XPS2_GIER_GIE_MASK 0x80000000 | 68 | #define XPS2_GIER_GIE_MASK 0x80000000 |
| 69 | 69 | ||
| 70 | struct xps2data { | 70 | struct xps2data { |
| 71 | int irq; | 71 | int irq; |
| 72 | u32 phys_addr; | ||
| 73 | u32 remap_size; | ||
| 74 | spinlock_t lock; | 72 | spinlock_t lock; |
| 75 | u8 rxb; /* Rx buffer */ | ||
| 76 | void __iomem *base_address; /* virt. address of control registers */ | 73 | void __iomem *base_address; /* virt. address of control registers */ |
| 77 | unsigned int dfl; | 74 | unsigned int flags; |
| 78 | struct serio serio; /* serio */ | 75 | struct serio serio; /* serio */ |
| 79 | }; | 76 | }; |
| 80 | 77 | ||
| @@ -82,8 +79,13 @@ struct xps2data { | |||
| 82 | /* XPS PS/2 data transmission calls */ | 79 | /* XPS PS/2 data transmission calls */ |
| 83 | /************************************/ | 80 | /************************************/ |
| 84 | 81 | ||
| 85 | /* | 82 | /** |
| 86 | * xps2_recv() will attempt to receive a byte of data from the PS/2 port. | 83 | * xps2_recv() - attempts to receive a byte from the PS/2 port. |
| 84 | * @drvdata: pointer to ps2 device private data structure | ||
| 85 | * @byte: address where the read data will be copied | ||
| 86 | * | ||
| 87 | * If there is any data available in the PS/2 receiver, this functions reads | ||
| 88 | * the data, otherwise it returns error. | ||
| 87 | */ | 89 | */ |
| 88 | static int xps2_recv(struct xps2data *drvdata, u8 *byte) | 90 | static int xps2_recv(struct xps2data *drvdata, u8 *byte) |
| 89 | { | 91 | { |
| @@ -116,33 +118,27 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id) | |||
| 116 | 118 | ||
| 117 | /* Check which interrupt is active */ | 119 | /* Check which interrupt is active */ |
| 118 | if (intr_sr & XPS2_IPIXR_RX_OVF) | 120 | if (intr_sr & XPS2_IPIXR_RX_OVF) |
| 119 | printk(KERN_WARNING "%s: receive overrun error\n", | 121 | dev_warn(drvdata->serio.dev.parent, "receive overrun error\n"); |
| 120 | drvdata->serio.name); | ||
| 121 | 122 | ||
| 122 | if (intr_sr & XPS2_IPIXR_RX_ERR) | 123 | if (intr_sr & XPS2_IPIXR_RX_ERR) |
| 123 | drvdata->dfl |= SERIO_PARITY; | 124 | drvdata->flags |= SERIO_PARITY; |
| 124 | 125 | ||
| 125 | if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT)) | 126 | if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT)) |
| 126 | drvdata->dfl |= SERIO_TIMEOUT; | 127 | drvdata->flags |= SERIO_TIMEOUT; |
| 127 | 128 | ||
| 128 | if (intr_sr & XPS2_IPIXR_RX_FULL) { | 129 | if (intr_sr & XPS2_IPIXR_RX_FULL) { |
| 129 | status = xps2_recv(drvdata, &drvdata->rxb); | 130 | status = xps2_recv(drvdata, &c); |
| 130 | 131 | ||
| 131 | /* Error, if a byte is not received */ | 132 | /* Error, if a byte is not received */ |
| 132 | if (status) { | 133 | if (status) { |
| 133 | printk(KERN_ERR | 134 | dev_err(drvdata->serio.dev.parent, |
| 134 | "%s: wrong rcvd byte count (%d)\n", | 135 | "wrong rcvd byte count (%d)\n", status); |
| 135 | drvdata->serio.name, status); | ||
| 136 | } else { | 136 | } else { |
| 137 | c = drvdata->rxb; | 137 | serio_interrupt(&drvdata->serio, c, drvdata->flags); |
| 138 | serio_interrupt(&drvdata->serio, c, drvdata->dfl); | 138 | drvdata->flags = 0; |
| 139 | drvdata->dfl = 0; | ||
| 140 | } | 139 | } |
| 141 | } | 140 | } |
| 142 | 141 | ||
| 143 | if (intr_sr & XPS2_IPIXR_TX_ACK) | ||
| 144 | drvdata->dfl = 0; | ||
| 145 | |||
| 146 | return IRQ_HANDLED; | 142 | return IRQ_HANDLED; |
| 147 | } | 143 | } |
| 148 | 144 | ||
| @@ -150,8 +146,15 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id) | |||
| 150 | /* serio callbacks */ | 146 | /* serio callbacks */ |
| 151 | /*******************/ | 147 | /*******************/ |
| 152 | 148 | ||
| 153 | /* | 149 | /** |
| 154 | * sxps2_write() sends a byte out through the PS/2 interface. | 150 | * sxps2_write() - sends a byte out through the PS/2 port. |
| 151 | * @pserio: pointer to the serio structure of the PS/2 port | ||
| 152 | * @c: data that needs to be written to the PS/2 port | ||
| 153 | * | ||
| 154 | * This function checks if the PS/2 transmitter is empty and sends a byte. | ||
| 155 | * Otherwise it returns error. Transmission fails only when nothing is connected | ||
| 156 | * to the PS/2 port. Thats why, we do not try to resend the data in case of a | ||
| 157 | * failure. | ||
| 155 | */ | 158 | */ |
| 156 | static int sxps2_write(struct serio *pserio, unsigned char c) | 159 | static int sxps2_write(struct serio *pserio, unsigned char c) |
| 157 | { | 160 | { |
| @@ -174,33 +177,39 @@ static int sxps2_write(struct serio *pserio, unsigned char c) | |||
| 174 | return status; | 177 | return status; |
| 175 | } | 178 | } |
| 176 | 179 | ||
| 177 | /* | 180 | /** |
| 178 | * sxps2_open() is called when a port is open by the higher layer. | 181 | * sxps2_open() - called when a port is opened by the higher layer. |
| 182 | * @pserio: pointer to the serio structure of the PS/2 device | ||
| 183 | * | ||
| 184 | * This function requests irq and enables interrupts for the PS/2 device. | ||
| 179 | */ | 185 | */ |
| 180 | static int sxps2_open(struct serio *pserio) | 186 | static int sxps2_open(struct serio *pserio) |
| 181 | { | 187 | { |
| 182 | struct xps2data *drvdata = pserio->port_data; | 188 | struct xps2data *drvdata = pserio->port_data; |
| 183 | int retval; | 189 | int error; |
| 190 | u8 c; | ||
| 184 | 191 | ||
| 185 | retval = request_irq(drvdata->irq, &xps2_interrupt, 0, | 192 | error = request_irq(drvdata->irq, &xps2_interrupt, 0, |
| 186 | DRIVER_NAME, drvdata); | 193 | DRIVER_NAME, drvdata); |
| 187 | if (retval) { | 194 | if (error) { |
| 188 | printk(KERN_ERR | 195 | dev_err(drvdata->serio.dev.parent, |
| 189 | "%s: Couldn't allocate interrupt %d\n", | 196 | "Couldn't allocate interrupt %d\n", drvdata->irq); |
| 190 | drvdata->serio.name, drvdata->irq); | 197 | return error; |
| 191 | return retval; | ||
| 192 | } | 198 | } |
| 193 | 199 | ||
| 194 | /* start reception by enabling the interrupts */ | 200 | /* start reception by enabling the interrupts */ |
| 195 | out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK); | 201 | out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK); |
| 196 | out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL); | 202 | out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL); |
| 197 | (void)xps2_recv(drvdata, &drvdata->rxb); | 203 | (void)xps2_recv(drvdata, &c); |
| 198 | 204 | ||
| 199 | return 0; /* success */ | 205 | return 0; /* success */ |
| 200 | } | 206 | } |
| 201 | 207 | ||
| 202 | /* | 208 | /** |
| 203 | * sxps2_close() frees the interrupt. | 209 | * sxps2_close() - frees the interrupt. |
| 210 | * @pserio: pointer to the serio structure of the PS/2 device | ||
| 211 | * | ||
| 212 | * This function frees the irq and disables interrupts for the PS/2 device. | ||
| 204 | */ | 213 | */ |
| 205 | static void sxps2_close(struct serio *pserio) | 214 | static void sxps2_close(struct serio *pserio) |
| 206 | { | 215 | { |
| @@ -212,24 +221,41 @@ static void sxps2_close(struct serio *pserio) | |||
| 212 | free_irq(drvdata->irq, drvdata); | 221 | free_irq(drvdata->irq, drvdata); |
| 213 | } | 222 | } |
| 214 | 223 | ||
| 215 | /*********************/ | 224 | /** |
| 216 | /* Device setup code */ | 225 | * xps2_of_probe - probe method for the PS/2 device. |
| 217 | /*********************/ | 226 | * @of_dev: pointer to OF device structure |
| 218 | 227 | * @match: pointer to the stucture used for matching a device | |
| 219 | static int xps2_setup(struct device *dev, struct resource *regs_res, | 228 | * |
| 220 | struct resource *irq_res) | 229 | * This function probes the PS/2 device in the device tree. |
| 230 | * It initializes the driver data structure and the hardware. | ||
| 231 | * It returns 0, if the driver is bound to the PS/2 device, or a negative | ||
| 232 | * value if there is an error. | ||
| 233 | */ | ||
| 234 | static int __devinit xps2_of_probe(struct of_device *ofdev, | ||
| 235 | const struct of_device_id *match) | ||
| 221 | { | 236 | { |
| 237 | struct resource r_irq; /* Interrupt resources */ | ||
| 238 | struct resource r_mem; /* IO mem resources */ | ||
| 222 | struct xps2data *drvdata; | 239 | struct xps2data *drvdata; |
| 223 | struct serio *serio; | 240 | struct serio *serio; |
| 224 | unsigned long remap_size; | 241 | struct device *dev = &ofdev->dev; |
| 225 | int retval; | 242 | resource_size_t remap_size, phys_addr; |
| 243 | int error; | ||
| 244 | |||
| 245 | dev_info(dev, "Device Tree Probing \'%s\'\n", | ||
| 246 | ofdev->node->name); | ||
| 226 | 247 | ||
| 227 | if (!dev) | 248 | /* Get iospace for the device */ |
| 228 | return -EINVAL; | 249 | error = of_address_to_resource(ofdev->node, 0, &r_mem); |
| 250 | if (error) { | ||
| 251 | dev_err(dev, "invalid address\n"); | ||
| 252 | return error; | ||
| 253 | } | ||
| 229 | 254 | ||
| 230 | if (!regs_res || !irq_res) { | 255 | /* Get IRQ for the device */ |
| 231 | dev_err(dev, "IO resource(s) not found\n"); | 256 | if (of_irq_to_resource(ofdev->node, 0, &r_irq) == NO_IRQ) { |
| 232 | return -EINVAL; | 257 | dev_err(dev, "no IRQ found\n"); |
| 258 | return -ENODEV; | ||
| 233 | } | 259 | } |
| 234 | 260 | ||
| 235 | drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL); | 261 | drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL); |
| @@ -241,24 +267,23 @@ static int xps2_setup(struct device *dev, struct resource *regs_res, | |||
| 241 | dev_set_drvdata(dev, drvdata); | 267 | dev_set_drvdata(dev, drvdata); |
| 242 | 268 | ||
| 243 | spin_lock_init(&drvdata->lock); | 269 | spin_lock_init(&drvdata->lock); |
| 244 | drvdata->irq = irq_res->start; | 270 | drvdata->irq = r_irq.start; |
| 245 | 271 | ||
| 246 | remap_size = regs_res->end - regs_res->start + 1; | 272 | phys_addr = r_mem.start; |
| 247 | if (!request_mem_region(regs_res->start, remap_size, DRIVER_NAME)) { | 273 | remap_size = r_mem.end - r_mem.start + 1; |
| 248 | dev_err(dev, "Couldn't lock memory region at 0x%08X\n", | 274 | if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) { |
| 249 | (unsigned int)regs_res->start); | 275 | dev_err(dev, "Couldn't lock memory region at 0x%08llX\n", |
| 250 | retval = -EBUSY; | 276 | (unsigned long long)phys_addr); |
| 277 | error = -EBUSY; | ||
| 251 | goto failed1; | 278 | goto failed1; |
| 252 | } | 279 | } |
| 253 | 280 | ||
| 254 | /* Fill in configuration data and add them to the list */ | 281 | /* Fill in configuration data and add them to the list */ |
| 255 | drvdata->phys_addr = regs_res->start; | 282 | drvdata->base_address = ioremap(phys_addr, remap_size); |
| 256 | drvdata->remap_size = remap_size; | ||
| 257 | drvdata->base_address = ioremap(regs_res->start, remap_size); | ||
| 258 | if (drvdata->base_address == NULL) { | 283 | if (drvdata->base_address == NULL) { |
| 259 | dev_err(dev, "Couldn't ioremap memory at 0x%08X\n", | 284 | dev_err(dev, "Couldn't ioremap memory at 0x%08llX\n", |
| 260 | (unsigned int)regs_res->start); | 285 | (unsigned long long)phys_addr); |
| 261 | retval = -EFAULT; | 286 | error = -EFAULT; |
| 262 | goto failed2; | 287 | goto failed2; |
| 263 | } | 288 | } |
| 264 | 289 | ||
| @@ -269,8 +294,9 @@ static int xps2_setup(struct device *dev, struct resource *regs_res, | |||
| 269 | * we have the PS2 in a good state */ | 294 | * we have the PS2 in a good state */ |
| 270 | out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET); | 295 | out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET); |
| 271 | 296 | ||
| 272 | dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%p, irq=%d\n", | 297 | dev_info(dev, "Xilinx PS2 at 0x%08llX mapped to 0x%p, irq=%d\n", |
| 273 | drvdata->phys_addr, drvdata->base_address, drvdata->irq); | 298 | (unsigned long long)phys_addr, drvdata->base_address, |
| 299 | drvdata->irq); | ||
| 274 | 300 | ||
| 275 | serio = &drvdata->serio; | 301 | serio = &drvdata->serio; |
| 276 | serio->id.type = SERIO_8042; | 302 | serio->id.type = SERIO_8042; |
| @@ -280,71 +306,51 @@ static int xps2_setup(struct device *dev, struct resource *regs_res, | |||
| 280 | serio->port_data = drvdata; | 306 | serio->port_data = drvdata; |
| 281 | serio->dev.parent = dev; | 307 | serio->dev.parent = dev; |
| 282 | snprintf(serio->name, sizeof(serio->name), | 308 | snprintf(serio->name, sizeof(serio->name), |
| 283 | "Xilinx XPS PS/2 at %08X", drvdata->phys_addr); | 309 | "Xilinx XPS PS/2 at %08llX", (unsigned long long)phys_addr); |
| 284 | snprintf(serio->phys, sizeof(serio->phys), | 310 | snprintf(serio->phys, sizeof(serio->phys), |
| 285 | "xilinxps2/serio at %08X", drvdata->phys_addr); | 311 | "xilinxps2/serio at %08llX", (unsigned long long)phys_addr); |
| 312 | |||
| 286 | serio_register_port(serio); | 313 | serio_register_port(serio); |
| 287 | 314 | ||
| 288 | return 0; /* success */ | 315 | return 0; /* success */ |
| 289 | 316 | ||
| 290 | failed2: | 317 | failed2: |
| 291 | release_mem_region(regs_res->start, remap_size); | 318 | release_mem_region(phys_addr, remap_size); |
| 292 | failed1: | 319 | failed1: |
| 293 | kfree(drvdata); | 320 | kfree(drvdata); |
| 294 | dev_set_drvdata(dev, NULL); | 321 | dev_set_drvdata(dev, NULL); |
| 295 | 322 | ||
| 296 | return retval; | 323 | return error; |
| 297 | } | ||
| 298 | |||
| 299 | /***************************/ | ||
| 300 | /* OF Platform Bus Support */ | ||
| 301 | /***************************/ | ||
| 302 | |||
| 303 | static int __devinit xps2_of_probe(struct of_device *ofdev, const struct | ||
| 304 | of_device_id * match) | ||
| 305 | { | ||
| 306 | struct resource r_irq; /* Interrupt resources */ | ||
| 307 | struct resource r_mem; /* IO mem resources */ | ||
| 308 | int rc = 0; | ||
| 309 | |||
| 310 | printk(KERN_INFO "Device Tree Probing \'%s\'\n", | ||
| 311 | ofdev->node->name); | ||
| 312 | |||
| 313 | /* Get iospace for the device */ | ||
| 314 | rc = of_address_to_resource(ofdev->node, 0, &r_mem); | ||
| 315 | if (rc) { | ||
| 316 | dev_err(&ofdev->dev, "invalid address\n"); | ||
| 317 | return rc; | ||
| 318 | } | ||
| 319 | |||
| 320 | /* Get IRQ for the device */ | ||
| 321 | rc = of_irq_to_resource(ofdev->node, 0, &r_irq); | ||
| 322 | if (rc == NO_IRQ) { | ||
| 323 | dev_err(&ofdev->dev, "no IRQ found\n"); | ||
| 324 | return rc; | ||
| 325 | } | ||
| 326 | |||
| 327 | return xps2_setup(&ofdev->dev, &r_mem, &r_irq); | ||
| 328 | } | 324 | } |
| 329 | 325 | ||
| 326 | /** | ||
| 327 | * xps2_of_remove - unbinds the driver from the PS/2 device. | ||
| 328 | * @of_dev: pointer to OF device structure | ||
| 329 | * | ||
| 330 | * This function is called if a device is physically removed from the system or | ||
| 331 | * if the driver module is being unloaded. It frees any resources allocated to | ||
| 332 | * the device. | ||
| 333 | */ | ||
| 330 | static int __devexit xps2_of_remove(struct of_device *of_dev) | 334 | static int __devexit xps2_of_remove(struct of_device *of_dev) |
| 331 | { | 335 | { |
| 332 | struct device *dev = &of_dev->dev; | 336 | struct device *dev = &of_dev->dev; |
| 333 | struct xps2data *drvdata; | 337 | struct xps2data *drvdata = dev_get_drvdata(dev); |
| 334 | 338 | struct resource r_mem; /* IO mem resources */ | |
| 335 | if (!dev) | ||
| 336 | return -EINVAL; | ||
| 337 | |||
| 338 | drvdata = dev_get_drvdata(dev); | ||
| 339 | 339 | ||
| 340 | serio_unregister_port(&drvdata->serio); | 340 | serio_unregister_port(&drvdata->serio); |
| 341 | iounmap(drvdata->base_address); | 341 | iounmap(drvdata->base_address); |
| 342 | release_mem_region(drvdata->phys_addr, drvdata->remap_size); | 342 | |
| 343 | /* Get iospace of the device */ | ||
| 344 | if (of_address_to_resource(of_dev->node, 0, &r_mem)) | ||
| 345 | dev_err(dev, "invalid address\n"); | ||
| 346 | else | ||
| 347 | release_mem_region(r_mem.start, r_mem.end - r_mem.start + 1); | ||
| 348 | |||
| 343 | kfree(drvdata); | 349 | kfree(drvdata); |
| 344 | 350 | ||
| 345 | dev_set_drvdata(dev, NULL); | 351 | dev_set_drvdata(dev, NULL); |
| 346 | 352 | ||
| 347 | return 0; /* success */ | 353 | return 0; |
| 348 | } | 354 | } |
| 349 | 355 | ||
| 350 | /* Match table for of_platform binding */ | 356 | /* Match table for of_platform binding */ |
