diff options
Diffstat (limited to 'drivers/platform/x86/intel_scu_ipc.c')
| -rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 66 | 
1 files changed, 40 insertions, 26 deletions
| diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 6851d10d6582..a68df4133403 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -19,6 +19,7 @@  #include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/io.h> +#include <linux/iopoll.h>  #include <linux/module.h>  #include <linux/slab.h> @@ -231,19 +232,15 @@ static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset)  /* Wait till scu status is busy */  static inline int busy_loop(struct intel_scu_ipc_dev *scu)  { -	unsigned long end = jiffies + IPC_TIMEOUT; - -	do { -		u32 status; - -		status = ipc_read_status(scu); -		if (!(status & IPC_STATUS_BUSY)) -			return (status & IPC_STATUS_ERR) ? -EIO : 0; +	u8 status; +	int err; -		usleep_range(50, 100); -	} while (time_before(jiffies, end)); +	err = readx_poll_timeout(ipc_read_status, scu, status, !(status & IPC_STATUS_BUSY), +				 100, jiffies_to_usecs(IPC_TIMEOUT)); +	if (err) +		return err; -	return -ETIMEDOUT; +	return (status & IPC_STATUS_ERR) ? -EIO : 0;  }  /* Wait till ipc ioc interrupt is received or timeout in 10 HZ */ @@ -251,10 +248,12 @@ static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu)  {  	int status; -	if (!wait_for_completion_timeout(&scu->cmd_complete, IPC_TIMEOUT)) -		return -ETIMEDOUT; +	wait_for_completion_timeout(&scu->cmd_complete, IPC_TIMEOUT);  	status = ipc_read_status(scu); +	if (status & IPC_STATUS_BUSY) +		return -ETIMEDOUT; +  	if (status & IPC_STATUS_ERR)  		return -EIO; @@ -266,6 +265,24 @@ static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu)  	return scu->irq > 0 ? ipc_wait_for_interrupt(scu) : busy_loop(scu);  } +static struct intel_scu_ipc_dev *intel_scu_ipc_get(struct intel_scu_ipc_dev *scu) +{ +	u8 status; + +	if (!scu) +		scu = ipcdev; +	if (!scu) +		return ERR_PTR(-ENODEV); + +	status = ipc_read_status(scu); +	if (status & IPC_STATUS_BUSY) { +		dev_dbg(&scu->dev, "device is busy\n"); +		return ERR_PTR(-EBUSY); +	} + +	return scu; +} +  /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */  static int pwr_reg_rdwr(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data,  			u32 count, u32 op, u32 id) @@ -279,11 +296,10 @@ static int pwr_reg_rdwr(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data,  	memset(cbuf, 0, sizeof(cbuf));  	mutex_lock(&ipclock); -	if (!scu) -		scu = ipcdev; -	if (!scu) { +	scu = intel_scu_ipc_get(scu); +	if (IS_ERR(scu)) {  		mutex_unlock(&ipclock); -		return -ENODEV; +		return PTR_ERR(scu);  	}  	for (nc = 0; nc < count; nc++, offset += 2) { @@ -438,13 +454,12 @@ int intel_scu_ipc_dev_simple_command(struct intel_scu_ipc_dev *scu, int cmd,  	int err;  	mutex_lock(&ipclock); -	if (!scu) -		scu = ipcdev; -	if (!scu) { +	scu = intel_scu_ipc_get(scu); +	if (IS_ERR(scu)) {  		mutex_unlock(&ipclock); -		return -ENODEV; +		return PTR_ERR(scu);  	} -	scu = ipcdev; +  	cmdval = sub << 12 | cmd;  	ipc_command(scu, cmdval);  	err = intel_scu_ipc_check_status(scu); @@ -484,11 +499,10 @@ int intel_scu_ipc_dev_command_with_size(struct intel_scu_ipc_dev *scu, int cmd,  		return -EINVAL;  	mutex_lock(&ipclock); -	if (!scu) -		scu = ipcdev; -	if (!scu) { +	scu = intel_scu_ipc_get(scu); +	if (IS_ERR(scu)) {  		mutex_unlock(&ipclock); -		return -ENODEV; +		return PTR_ERR(scu);  	}  	memcpy(inbuf, in, inlen); |