| .. | .. |
|---|
| 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); |
|---|