.. | .. |
---|
19 | 19 | #include <linux/init.h> |
---|
20 | 20 | #include <linux/interrupt.h> |
---|
21 | 21 | #include <linux/io.h> |
---|
| 22 | +#include <linux/iopoll.h> |
---|
22 | 23 | #include <linux/module.h> |
---|
23 | 24 | #include <linux/slab.h> |
---|
24 | 25 | |
---|
.. | .. |
---|
232 | 233 | /* Wait till scu status is busy */ |
---|
233 | 234 | static inline int busy_loop(struct intel_scu_ipc_dev *scu) |
---|
234 | 235 | { |
---|
235 | | - unsigned long end = jiffies + IPC_TIMEOUT; |
---|
| 236 | + u8 status; |
---|
| 237 | + int err; |
---|
236 | 238 | |
---|
237 | | - do { |
---|
238 | | - u32 status; |
---|
| 239 | + err = readx_poll_timeout(ipc_read_status, scu, status, !(status & IPC_STATUS_BUSY), |
---|
| 240 | + 100, jiffies_to_usecs(IPC_TIMEOUT)); |
---|
| 241 | + if (err) |
---|
| 242 | + return err; |
---|
239 | 243 | |
---|
240 | | - status = ipc_read_status(scu); |
---|
241 | | - if (!(status & IPC_STATUS_BUSY)) |
---|
242 | | - return (status & IPC_STATUS_ERR) ? -EIO : 0; |
---|
243 | | - |
---|
244 | | - usleep_range(50, 100); |
---|
245 | | - } while (time_before(jiffies, end)); |
---|
246 | | - |
---|
247 | | - return -ETIMEDOUT; |
---|
| 244 | + return (status & IPC_STATUS_ERR) ? -EIO : 0; |
---|
248 | 245 | } |
---|
249 | 246 | |
---|
250 | 247 | /* Wait till ipc ioc interrupt is received or timeout in 10 HZ */ |
---|
.. | .. |
---|
252 | 249 | { |
---|
253 | 250 | int status; |
---|
254 | 251 | |
---|
255 | | - if (!wait_for_completion_timeout(&scu->cmd_complete, IPC_TIMEOUT)) |
---|
256 | | - return -ETIMEDOUT; |
---|
| 252 | + wait_for_completion_timeout(&scu->cmd_complete, IPC_TIMEOUT); |
---|
257 | 253 | |
---|
258 | 254 | status = ipc_read_status(scu); |
---|
| 255 | + if (status & IPC_STATUS_BUSY) |
---|
| 256 | + return -ETIMEDOUT; |
---|
| 257 | + |
---|
259 | 258 | if (status & IPC_STATUS_ERR) |
---|
260 | 259 | return -EIO; |
---|
261 | 260 | |
---|
.. | .. |
---|
265 | 264 | static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu) |
---|
266 | 265 | { |
---|
267 | 266 | return scu->irq > 0 ? ipc_wait_for_interrupt(scu) : busy_loop(scu); |
---|
| 267 | +} |
---|
| 268 | + |
---|
| 269 | +static struct intel_scu_ipc_dev *intel_scu_ipc_get(struct intel_scu_ipc_dev *scu) |
---|
| 270 | +{ |
---|
| 271 | + u8 status; |
---|
| 272 | + |
---|
| 273 | + if (!scu) |
---|
| 274 | + scu = ipcdev; |
---|
| 275 | + if (!scu) |
---|
| 276 | + return ERR_PTR(-ENODEV); |
---|
| 277 | + |
---|
| 278 | + status = ipc_read_status(scu); |
---|
| 279 | + if (status & IPC_STATUS_BUSY) { |
---|
| 280 | + dev_dbg(&scu->dev, "device is busy\n"); |
---|
| 281 | + return ERR_PTR(-EBUSY); |
---|
| 282 | + } |
---|
| 283 | + |
---|
| 284 | + return scu; |
---|
268 | 285 | } |
---|
269 | 286 | |
---|
270 | 287 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ |
---|
.. | .. |
---|
280 | 297 | memset(cbuf, 0, sizeof(cbuf)); |
---|
281 | 298 | |
---|
282 | 299 | mutex_lock(&ipclock); |
---|
283 | | - if (!scu) |
---|
284 | | - scu = ipcdev; |
---|
285 | | - if (!scu) { |
---|
| 300 | + scu = intel_scu_ipc_get(scu); |
---|
| 301 | + if (IS_ERR(scu)) { |
---|
286 | 302 | mutex_unlock(&ipclock); |
---|
287 | | - return -ENODEV; |
---|
| 303 | + return PTR_ERR(scu); |
---|
288 | 304 | } |
---|
289 | 305 | |
---|
290 | 306 | for (nc = 0; nc < count; nc++, offset += 2) { |
---|
.. | .. |
---|
439 | 455 | int err; |
---|
440 | 456 | |
---|
441 | 457 | mutex_lock(&ipclock); |
---|
442 | | - if (!scu) |
---|
443 | | - scu = ipcdev; |
---|
444 | | - if (!scu) { |
---|
| 458 | + scu = intel_scu_ipc_get(scu); |
---|
| 459 | + if (IS_ERR(scu)) { |
---|
445 | 460 | mutex_unlock(&ipclock); |
---|
446 | | - return -ENODEV; |
---|
| 461 | + return PTR_ERR(scu); |
---|
447 | 462 | } |
---|
448 | | - scu = ipcdev; |
---|
| 463 | + |
---|
449 | 464 | cmdval = sub << 12 | cmd; |
---|
450 | 465 | ipc_command(scu, cmdval); |
---|
451 | 466 | err = intel_scu_ipc_check_status(scu); |
---|
.. | .. |
---|
485 | 500 | return -EINVAL; |
---|
486 | 501 | |
---|
487 | 502 | mutex_lock(&ipclock); |
---|
488 | | - if (!scu) |
---|
489 | | - scu = ipcdev; |
---|
490 | | - if (!scu) { |
---|
| 503 | + scu = intel_scu_ipc_get(scu); |
---|
| 504 | + if (IS_ERR(scu)) { |
---|
491 | 505 | mutex_unlock(&ipclock); |
---|
492 | | - return -ENODEV; |
---|
| 506 | + return PTR_ERR(scu); |
---|
493 | 507 | } |
---|
494 | 508 | |
---|
495 | 509 | memcpy(inbuf, in, inlen); |
---|
.. | .. |
---|
583 | 597 | scu->dev.parent = parent; |
---|
584 | 598 | scu->dev.class = &intel_scu_ipc_class; |
---|
585 | 599 | scu->dev.release = intel_scu_ipc_release; |
---|
586 | | - dev_set_name(&scu->dev, "intel_scu_ipc"); |
---|
587 | 600 | |
---|
588 | 601 | if (!request_mem_region(scu_data->mem.start, resource_size(&scu_data->mem), |
---|
589 | 602 | "intel_scu_ipc")) { |
---|
.. | .. |
---|
612 | 625 | * After this point intel_scu_ipc_release() takes care of |
---|
613 | 626 | * releasing the SCU IPC resources once refcount drops to zero. |
---|
614 | 627 | */ |
---|
| 628 | + dev_set_name(&scu->dev, "intel_scu_ipc"); |
---|
615 | 629 | err = device_register(&scu->dev); |
---|
616 | 630 | if (err) { |
---|
617 | 631 | put_device(&scu->dev); |
---|