xref: /openbmc/linux/drivers/platform/x86/intel_scu_ipc.c (revision 3a457d2804d4c7e76cb4492c6787fdfb7203fc7d)
19b748e0eSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0
29a58a333SSreedhara DS /*
39b748e0eSAndy Shevchenko  * Driver for the Intel SCU IPC mechanism
49a58a333SSreedhara DS  *
57c2e3c74SAndy Shevchenko  * (C) Copyright 2008-2010,2015 Intel Corporation
69a58a333SSreedhara DS  * Author: Sreedhara DS (sreedhara.ds@intel.com)
79a58a333SSreedhara DS  *
8c8440336SLucas De Marchi  * SCU running in ARC processor communicates with other entity running in IA
99a58a333SSreedhara DS  * core through IPC mechanism which in turn messaging between IA core ad SCU.
109a58a333SSreedhara DS  * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and
119a58a333SSreedhara DS  * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with
129a58a333SSreedhara DS  * IPC-1 Driver provides an API for power control unit registers (e.g. MSIC)
139a58a333SSreedhara DS  * along with other APIs.
149a58a333SSreedhara DS  */
152d0554e8SAndy Shevchenko 
169a58a333SSreedhara DS #include <linux/delay.h>
172d0554e8SAndy Shevchenko #include <linux/device.h>
189a58a333SSreedhara DS #include <linux/errno.h>
199a58a333SSreedhara DS #include <linux/init.h>
209a58a333SSreedhara DS #include <linux/interrupt.h>
2154b34aa0SMika Westerberg #include <linux/io.h>
22e0b4ab3bSStephen Boyd #include <linux/iopoll.h>
2354b34aa0SMika Westerberg #include <linux/module.h>
2454b34aa0SMika Westerberg #include <linux/slab.h>
252d0554e8SAndy Shevchenko 
269a58a333SSreedhara DS #include <asm/intel_scu_ipc.h>
279a58a333SSreedhara DS 
289a58a333SSreedhara DS /* IPC defines the following message types */
2959aa78e3SMika Westerberg #define IPCMSG_PCNTRL         0xff /* Power controller unit read/write */
309a58a333SSreedhara DS 
319a58a333SSreedhara DS /* Command id associated with message IPCMSG_PCNTRL */
329a58a333SSreedhara DS #define IPC_CMD_PCNTRL_W      0 /* Register write */
339a58a333SSreedhara DS #define IPC_CMD_PCNTRL_R      1 /* Register read */
349a58a333SSreedhara DS #define IPC_CMD_PCNTRL_M      2 /* Register read-modify-write */
359a58a333SSreedhara DS 
369a58a333SSreedhara DS /*
379a58a333SSreedhara DS  * IPC register summary
389a58a333SSreedhara DS  *
3932d0e4a3SAndy Shevchenko  * IPC register blocks are memory mapped at fixed address of PCI BAR 0.
409a58a333SSreedhara DS  * To read or write information to the SCU, driver writes to IPC-1 memory
4132d0e4a3SAndy Shevchenko  * mapped registers. The following is the IPC mechanism
429a58a333SSreedhara DS  *
439a58a333SSreedhara DS  * 1. IA core cDMI interface claims this transaction and converts it to a
449a58a333SSreedhara DS  *    Transaction Layer Packet (TLP) message which is sent across the cDMI.
459a58a333SSreedhara DS  *
469a58a333SSreedhara DS  * 2. South Complex cDMI block receives this message and writes it to
479a58a333SSreedhara DS  *    the IPC-1 register block, causing an interrupt to the SCU
489a58a333SSreedhara DS  *
499a58a333SSreedhara DS  * 3. SCU firmware decodes this interrupt and IPC message and the appropriate
509a58a333SSreedhara DS  *    message handler is called within firmware.
519a58a333SSreedhara DS  */
529a58a333SSreedhara DS 
5351cd525dSArjan van de Ven #define IPC_WWBUF_SIZE    20		/* IPC Write buffer Size */
5451cd525dSArjan van de Ven #define IPC_RWBUF_SIZE    20		/* IPC Read buffer Size */
55ed12f295SKuppuswamy Sathyanarayanan #define IPC_IOC	          0x100		/* IPC command register IOC bit */
56e97a1c98SKuppuswamy Sathyanarayanan 
579a58a333SSreedhara DS struct intel_scu_ipc_dev {
5854b34aa0SMika Westerberg 	struct device dev;
5954b34aa0SMika Westerberg 	struct resource mem;
60f57fa185SMika Westerberg 	struct module *owner;
6154b34aa0SMika Westerberg 	int irq;
629a58a333SSreedhara DS 	void __iomem *ipc_base;
63ed12f295SKuppuswamy Sathyanarayanan 	struct completion cmd_complete;
649a58a333SSreedhara DS };
659a58a333SSreedhara DS 
66e48b72a5SMika Westerberg #define IPC_STATUS		0x04
67e48b72a5SMika Westerberg #define IPC_STATUS_IRQ		BIT(2)
6819e2d350SMika Westerberg #define IPC_STATUS_ERR		BIT(1)
6919e2d350SMika Westerberg #define IPC_STATUS_BUSY		BIT(0)
70e48b72a5SMika Westerberg 
719a58a333SSreedhara DS /*
7219e2d350SMika Westerberg  * IPC Write/Read Buffers:
7319e2d350SMika Westerberg  * 16 byte buffer for sending and receiving data to and from SCU.
749a58a333SSreedhara DS  */
7519e2d350SMika Westerberg #define IPC_WRITE_BUFFER	0x80
769a58a333SSreedhara DS #define IPC_READ_BUFFER		0x90
779a58a333SSreedhara DS 
78e7b7ab38SMika Westerberg /* Timeout in jiffies */
795c02b581SPrashant Malani #define IPC_TIMEOUT		(10 * HZ)
80e7b7ab38SMika Westerberg 
8154b34aa0SMika Westerberg static struct intel_scu_ipc_dev *ipcdev; /* Only one for now */
829a58a333SSreedhara DS static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
839a58a333SSreedhara DS 
8454b34aa0SMika Westerberg static struct class intel_scu_ipc_class = {
8554b34aa0SMika Westerberg 	.name = "intel_scu_ipc",
8654b34aa0SMika Westerberg };
8754b34aa0SMika Westerberg 
88f57fa185SMika Westerberg /**
89f57fa185SMika Westerberg  * intel_scu_ipc_dev_get() - Get SCU IPC instance
90f57fa185SMika Westerberg  *
91f57fa185SMika Westerberg  * The recommended new API takes SCU IPC instance as parameter and this
92f57fa185SMika Westerberg  * function can be called by driver to get the instance. This also makes
93f57fa185SMika Westerberg  * sure the driver providing the IPC functionality cannot be unloaded
94f57fa185SMika Westerberg  * while the caller has the instance.
95f57fa185SMika Westerberg  *
96f57fa185SMika Westerberg  * Call intel_scu_ipc_dev_put() to release the instance.
97f57fa185SMika Westerberg  *
98f57fa185SMika Westerberg  * Returns %NULL if SCU IPC is not currently available.
99f57fa185SMika Westerberg  */
intel_scu_ipc_dev_get(void)100f57fa185SMika Westerberg struct intel_scu_ipc_dev *intel_scu_ipc_dev_get(void)
101f57fa185SMika Westerberg {
102f57fa185SMika Westerberg 	struct intel_scu_ipc_dev *scu = NULL;
103f57fa185SMika Westerberg 
104f57fa185SMika Westerberg 	mutex_lock(&ipclock);
105f57fa185SMika Westerberg 	if (ipcdev) {
106f57fa185SMika Westerberg 		get_device(&ipcdev->dev);
107f57fa185SMika Westerberg 		/*
108f57fa185SMika Westerberg 		 * Prevent the IPC provider from being unloaded while it
109f57fa185SMika Westerberg 		 * is being used.
110f57fa185SMika Westerberg 		 */
111f57fa185SMika Westerberg 		if (!try_module_get(ipcdev->owner))
112f57fa185SMika Westerberg 			put_device(&ipcdev->dev);
113f57fa185SMika Westerberg 		else
114f57fa185SMika Westerberg 			scu = ipcdev;
115f57fa185SMika Westerberg 	}
116f57fa185SMika Westerberg 
117f57fa185SMika Westerberg 	mutex_unlock(&ipclock);
118f57fa185SMika Westerberg 	return scu;
119f57fa185SMika Westerberg }
120f57fa185SMika Westerberg EXPORT_SYMBOL_GPL(intel_scu_ipc_dev_get);
121f57fa185SMika Westerberg 
122f57fa185SMika Westerberg /**
123f57fa185SMika Westerberg  * intel_scu_ipc_dev_put() - Put SCU IPC instance
124f57fa185SMika Westerberg  * @scu: SCU IPC instance
125f57fa185SMika Westerberg  *
126f57fa185SMika Westerberg  * This function releases the SCU IPC instance retrieved from
127f57fa185SMika Westerberg  * intel_scu_ipc_dev_get() and allows the driver providing IPC to be
128f57fa185SMika Westerberg  * unloaded.
129f57fa185SMika Westerberg  */
intel_scu_ipc_dev_put(struct intel_scu_ipc_dev * scu)130f57fa185SMika Westerberg void intel_scu_ipc_dev_put(struct intel_scu_ipc_dev *scu)
131f57fa185SMika Westerberg {
132f57fa185SMika Westerberg 	if (scu) {
133f57fa185SMika Westerberg 		module_put(scu->owner);
134f57fa185SMika Westerberg 		put_device(&scu->dev);
135f57fa185SMika Westerberg 	}
136f57fa185SMika Westerberg }
137f57fa185SMika Westerberg EXPORT_SYMBOL_GPL(intel_scu_ipc_dev_put);
138f57fa185SMika Westerberg 
139f57fa185SMika Westerberg struct intel_scu_ipc_devres {
140f57fa185SMika Westerberg 	struct intel_scu_ipc_dev *scu;
141f57fa185SMika Westerberg };
142f57fa185SMika Westerberg 
devm_intel_scu_ipc_dev_release(struct device * dev,void * res)143f57fa185SMika Westerberg static void devm_intel_scu_ipc_dev_release(struct device *dev, void *res)
144f57fa185SMika Westerberg {
145f57fa185SMika Westerberg 	struct intel_scu_ipc_devres *dr = res;
146f57fa185SMika Westerberg 	struct intel_scu_ipc_dev *scu = dr->scu;
147f57fa185SMika Westerberg 
148f57fa185SMika Westerberg 	intel_scu_ipc_dev_put(scu);
149f57fa185SMika Westerberg }
150f57fa185SMika Westerberg 
151f57fa185SMika Westerberg /**
152f57fa185SMika Westerberg  * devm_intel_scu_ipc_dev_get() - Allocate managed SCU IPC device
153f57fa185SMika Westerberg  * @dev: Device requesting the SCU IPC device
154f57fa185SMika Westerberg  *
155f57fa185SMika Westerberg  * The recommended new API takes SCU IPC instance as parameter and this
156f57fa185SMika Westerberg  * function can be called by driver to get the instance. This also makes
157f57fa185SMika Westerberg  * sure the driver providing the IPC functionality cannot be unloaded
158f57fa185SMika Westerberg  * while the caller has the instance.
159f57fa185SMika Westerberg  *
160f57fa185SMika Westerberg  * Returns %NULL if SCU IPC is not currently available.
161f57fa185SMika Westerberg  */
devm_intel_scu_ipc_dev_get(struct device * dev)162f57fa185SMika Westerberg struct intel_scu_ipc_dev *devm_intel_scu_ipc_dev_get(struct device *dev)
163f57fa185SMika Westerberg {
164f57fa185SMika Westerberg 	struct intel_scu_ipc_devres *dr;
165f57fa185SMika Westerberg 	struct intel_scu_ipc_dev *scu;
166f57fa185SMika Westerberg 
167f57fa185SMika Westerberg 	dr = devres_alloc(devm_intel_scu_ipc_dev_release, sizeof(*dr), GFP_KERNEL);
168f57fa185SMika Westerberg 	if (!dr)
169f57fa185SMika Westerberg 		return NULL;
170f57fa185SMika Westerberg 
171f57fa185SMika Westerberg 	scu = intel_scu_ipc_dev_get();
172f57fa185SMika Westerberg 	if (!scu) {
173f57fa185SMika Westerberg 		devres_free(dr);
174f57fa185SMika Westerberg 		return NULL;
175f57fa185SMika Westerberg 	}
176f57fa185SMika Westerberg 
177f57fa185SMika Westerberg 	dr->scu = scu;
178f57fa185SMika Westerberg 	devres_add(dev, dr);
179f57fa185SMika Westerberg 
180f57fa185SMika Westerberg 	return scu;
181f57fa185SMika Westerberg }
182f57fa185SMika Westerberg EXPORT_SYMBOL_GPL(devm_intel_scu_ipc_dev_get);
183f57fa185SMika Westerberg 
1849a58a333SSreedhara DS /*
185b0b3f578SAndy Shevchenko  * Send ipc command
1869a58a333SSreedhara DS  * Command Register (Write Only):
1879a58a333SSreedhara DS  * A write to this register results in an interrupt to the SCU core processor
1889a58a333SSreedhara DS  * Format:
1899a58a333SSreedhara DS  * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)|
1909a58a333SSreedhara DS  */
ipc_command(struct intel_scu_ipc_dev * scu,u32 cmd)191b0b3f578SAndy Shevchenko static inline void ipc_command(struct intel_scu_ipc_dev *scu, u32 cmd)
1929a58a333SSreedhara DS {
193b0b3f578SAndy Shevchenko 	reinit_completion(&scu->cmd_complete);
194b0b3f578SAndy Shevchenko 	writel(cmd | IPC_IOC, scu->ipc_base);
195ed12f295SKuppuswamy Sathyanarayanan }
1969a58a333SSreedhara DS 
1979a58a333SSreedhara DS /*
198b0b3f578SAndy Shevchenko  * Write ipc data
1999a58a333SSreedhara DS  * IPC Write Buffer (Write Only):
2009a58a333SSreedhara DS  * 16-byte buffer for sending data associated with IPC command to
2019a58a333SSreedhara DS  * SCU. Size of the data is specified in the IPC_COMMAND_REG register
2029a58a333SSreedhara DS  */
ipc_data_writel(struct intel_scu_ipc_dev * scu,u32 data,u32 offset)203b0b3f578SAndy Shevchenko static inline void ipc_data_writel(struct intel_scu_ipc_dev *scu, u32 data, u32 offset)
2049a58a333SSreedhara DS {
20519e2d350SMika Westerberg 	writel(data, scu->ipc_base + IPC_WRITE_BUFFER + offset);
2069a58a333SSreedhara DS }
2079a58a333SSreedhara DS 
2089a58a333SSreedhara DS /*
2099a58a333SSreedhara DS  * Status Register (Read Only):
2109a58a333SSreedhara DS  * Driver will read this register to get the ready/busy status of the IPC
2119a58a333SSreedhara DS  * block and error status of the IPC command that was just processed by SCU
2129a58a333SSreedhara DS  * Format:
2139a58a333SSreedhara DS  * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
2149a58a333SSreedhara DS  */
ipc_read_status(struct intel_scu_ipc_dev * scu)215b0b3f578SAndy Shevchenko static inline u8 ipc_read_status(struct intel_scu_ipc_dev *scu)
2169a58a333SSreedhara DS {
21719e2d350SMika Westerberg 	return __raw_readl(scu->ipc_base + IPC_STATUS);
2189a58a333SSreedhara DS }
2199a58a333SSreedhara DS 
220b0b3f578SAndy Shevchenko /* Read ipc byte data */
ipc_data_readb(struct intel_scu_ipc_dev * scu,u32 offset)221b0b3f578SAndy Shevchenko static inline u8 ipc_data_readb(struct intel_scu_ipc_dev *scu, u32 offset)
2229a58a333SSreedhara DS {
223b0b3f578SAndy Shevchenko 	return readb(scu->ipc_base + IPC_READ_BUFFER + offset);
2249a58a333SSreedhara DS }
2259a58a333SSreedhara DS 
226b0b3f578SAndy Shevchenko /* Read ipc u32 data */
ipc_data_readl(struct intel_scu_ipc_dev * scu,u32 offset)227b0b3f578SAndy Shevchenko static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset)
2289a58a333SSreedhara DS {
229b0b3f578SAndy Shevchenko 	return readl(scu->ipc_base + IPC_READ_BUFFER + offset);
2309a58a333SSreedhara DS }
2319a58a333SSreedhara DS 
2327c2e3c74SAndy Shevchenko /* Wait till scu status is busy */
busy_loop(struct intel_scu_ipc_dev * scu)233b0b3f578SAndy Shevchenko static inline int busy_loop(struct intel_scu_ipc_dev *scu)
2349a58a333SSreedhara DS {
235e0b4ab3bSStephen Boyd 	u8 status;
236e0b4ab3bSStephen Boyd 	int err;
2379a58a333SSreedhara DS 
238e0b4ab3bSStephen Boyd 	err = readx_poll_timeout(ipc_read_status, scu, status, !(status & IPC_STATUS_BUSY),
239e0b4ab3bSStephen Boyd 				 100, jiffies_to_usecs(IPC_TIMEOUT));
240e0b4ab3bSStephen Boyd 	if (err)
241e0b4ab3bSStephen Boyd 		return err;
242e7b7ab38SMika Westerberg 
243e7b7ab38SMika Westerberg 	return (status & IPC_STATUS_ERR) ? -EIO : 0;
2449a58a333SSreedhara DS }
245f0295a36SAndy Shevchenko 
246a0c5814bSPrashant Malani /* Wait till ipc ioc interrupt is received or timeout in 10 HZ */
ipc_wait_for_interrupt(struct intel_scu_ipc_dev * scu)247b0b3f578SAndy Shevchenko static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu)
248ed12f295SKuppuswamy Sathyanarayanan {
249ed12f295SKuppuswamy Sathyanarayanan 	int status;
250ed12f295SKuppuswamy Sathyanarayanan 
251427fada6SStephen Boyd 	wait_for_completion_timeout(&scu->cmd_complete, IPC_TIMEOUT);
252ed12f295SKuppuswamy Sathyanarayanan 
253b0b3f578SAndy Shevchenko 	status = ipc_read_status(scu);
254427fada6SStephen Boyd 	if (status & IPC_STATUS_BUSY)
255427fada6SStephen Boyd 		return -ETIMEDOUT;
256427fada6SStephen Boyd 
25719e2d350SMika Westerberg 	if (status & IPC_STATUS_ERR)
258ed12f295SKuppuswamy Sathyanarayanan 		return -EIO;
259ed12f295SKuppuswamy Sathyanarayanan 
260ed12f295SKuppuswamy Sathyanarayanan 	return 0;
261ed12f295SKuppuswamy Sathyanarayanan }
262ed12f295SKuppuswamy Sathyanarayanan 
intel_scu_ipc_check_status(struct intel_scu_ipc_dev * scu)263b0b3f578SAndy Shevchenko static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu)
264ed12f295SKuppuswamy Sathyanarayanan {
26554b34aa0SMika Westerberg 	return scu->irq > 0 ? ipc_wait_for_interrupt(scu) : busy_loop(scu);
266ed12f295SKuppuswamy Sathyanarayanan }
267ed12f295SKuppuswamy Sathyanarayanan 
intel_scu_ipc_get(struct intel_scu_ipc_dev * scu)268*85e654c9SStephen Boyd static struct intel_scu_ipc_dev *intel_scu_ipc_get(struct intel_scu_ipc_dev *scu)
269*85e654c9SStephen Boyd {
270*85e654c9SStephen Boyd 	u8 status;
271*85e654c9SStephen Boyd 
272*85e654c9SStephen Boyd 	if (!scu)
273*85e654c9SStephen Boyd 		scu = ipcdev;
274*85e654c9SStephen Boyd 	if (!scu)
275*85e654c9SStephen Boyd 		return ERR_PTR(-ENODEV);
276*85e654c9SStephen Boyd 
277*85e654c9SStephen Boyd 	status = ipc_read_status(scu);
278*85e654c9SStephen Boyd 	if (status & IPC_STATUS_BUSY) {
279*85e654c9SStephen Boyd 		dev_dbg(&scu->dev, "device is busy\n");
280*85e654c9SStephen Boyd 		return ERR_PTR(-EBUSY);
281*85e654c9SStephen Boyd 	}
282*85e654c9SStephen Boyd 
283*85e654c9SStephen Boyd 	return scu;
284*85e654c9SStephen Boyd }
285*85e654c9SStephen Boyd 
2869a58a333SSreedhara DS /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
pwr_reg_rdwr(struct intel_scu_ipc_dev * scu,u16 * addr,u8 * data,u32 count,u32 op,u32 id)287f57fa185SMika Westerberg static int pwr_reg_rdwr(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data,
288f57fa185SMika Westerberg 			u32 count, u32 op, u32 id)
2899a58a333SSreedhara DS {
2904707375fSAlan Cox 	int nc;
2919a58a333SSreedhara DS 	u32 offset = 0;
292ecb5646cSAxel Lin 	int err;
2938642d7f8SChristophe JAILLET 	u8 cbuf[IPC_WWBUF_SIZE];
2949a58a333SSreedhara DS 	u32 *wbuf = (u32 *)&cbuf;
2959a58a333SSreedhara DS 
296ed6f2b4dSArjan van de Ven 	memset(cbuf, 0, sizeof(cbuf));
297ed6f2b4dSArjan van de Ven 
2988642d7f8SChristophe JAILLET 	mutex_lock(&ipclock);
299*85e654c9SStephen Boyd 	scu = intel_scu_ipc_get(scu);
300*85e654c9SStephen Boyd 	if (IS_ERR(scu)) {
3019a58a333SSreedhara DS 		mutex_unlock(&ipclock);
302*85e654c9SStephen Boyd 		return PTR_ERR(scu);
3039a58a333SSreedhara DS 	}
3049a58a333SSreedhara DS 
305e3359fd5SSreedhara DS 	for (nc = 0; nc < count; nc++, offset += 2) {
306e3359fd5SSreedhara DS 		cbuf[offset] = addr[nc];
307e3359fd5SSreedhara DS 		cbuf[offset + 1] = addr[nc] >> 8;
3089a58a333SSreedhara DS 	}
3099a58a333SSreedhara DS 
310e3359fd5SSreedhara DS 	if (id == IPC_CMD_PCNTRL_R) {
311e3359fd5SSreedhara DS 		for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
312b0b3f578SAndy Shevchenko 			ipc_data_writel(scu, wbuf[nc], offset);
313b0b3f578SAndy Shevchenko 		ipc_command(scu, (count * 2) << 16 | id << 12 | 0 << 8 | op);
314e3359fd5SSreedhara DS 	} else if (id == IPC_CMD_PCNTRL_W) {
315e3359fd5SSreedhara DS 		for (nc = 0; nc < count; nc++, offset += 1)
316e3359fd5SSreedhara DS 			cbuf[offset] = data[nc];
317e3359fd5SSreedhara DS 		for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
318b0b3f578SAndy Shevchenko 			ipc_data_writel(scu, wbuf[nc], offset);
319b0b3f578SAndy Shevchenko 		ipc_command(scu, (count * 3) << 16 | id << 12 | 0 << 8 | op);
320e3359fd5SSreedhara DS 	} else if (id == IPC_CMD_PCNTRL_M) {
321e3359fd5SSreedhara DS 		cbuf[offset] = data[0];
322e3359fd5SSreedhara DS 		cbuf[offset + 1] = data[1];
323b0b3f578SAndy Shevchenko 		ipc_data_writel(scu, wbuf[0], 0); /* Write wbuff */
324b0b3f578SAndy Shevchenko 		ipc_command(scu, 4 << 16 | id << 12 | 0 << 8 | op);
325e3359fd5SSreedhara DS 	}
3269a58a333SSreedhara DS 
327b0b3f578SAndy Shevchenko 	err = intel_scu_ipc_check_status(scu);
328c7094d1dSKuppuswamy Sathyanarayanan 	if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
3299a58a333SSreedhara DS 		/* Workaround: values are read as 0 without memcpy_fromio */
330b0b3f578SAndy Shevchenko 		memcpy_fromio(cbuf, scu->ipc_base + 0x90, 16);
3319a58a333SSreedhara DS 		for (nc = 0; nc < count; nc++)
332b0b3f578SAndy Shevchenko 			data[nc] = ipc_data_readb(scu, nc);
3339a58a333SSreedhara DS 	}
3349a58a333SSreedhara DS 	mutex_unlock(&ipclock);
3359a58a333SSreedhara DS 	return err;
3369a58a333SSreedhara DS }
3379a58a333SSreedhara DS 
3389a58a333SSreedhara DS /**
339f57fa185SMika Westerberg  * intel_scu_ipc_dev_ioread8() - Read a byte via the SCU
340f57fa185SMika Westerberg  * @scu: Optional SCU IPC instance
3418b236565SMika Westerberg  * @addr: Register on SCU
3428b236565SMika Westerberg  * @data: Return pointer for read byte
3439a58a333SSreedhara DS  *
3448b236565SMika Westerberg  * Read a single register. Returns %0 on success or an error code. All
3459a58a333SSreedhara DS  * locking between SCU accesses is handled for the caller.
3469a58a333SSreedhara DS  *
3479a58a333SSreedhara DS  * This function may sleep.
3489a58a333SSreedhara DS  */
intel_scu_ipc_dev_ioread8(struct intel_scu_ipc_dev * scu,u16 addr,u8 * data)349f57fa185SMika Westerberg int intel_scu_ipc_dev_ioread8(struct intel_scu_ipc_dev *scu, u16 addr, u8 *data)
3509a58a333SSreedhara DS {
351f57fa185SMika Westerberg 	return pwr_reg_rdwr(scu, &addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
3529a58a333SSreedhara DS }
353f57fa185SMika Westerberg EXPORT_SYMBOL(intel_scu_ipc_dev_ioread8);
3549a58a333SSreedhara DS 
3559a58a333SSreedhara DS /**
356f57fa185SMika Westerberg  * intel_scu_ipc_dev_iowrite8() - Write a byte via the SCU
357f57fa185SMika Westerberg  * @scu: Optional SCU IPC instance
3588b236565SMika Westerberg  * @addr: Register on SCU
3598b236565SMika Westerberg  * @data: Byte to write
3609a58a333SSreedhara DS  *
3618b236565SMika Westerberg  * Write a single register. Returns %0 on success or an error code. All
3629a58a333SSreedhara DS  * locking between SCU accesses is handled for the caller.
3639a58a333SSreedhara DS  *
3649a58a333SSreedhara DS  * This function may sleep.
3659a58a333SSreedhara DS  */
intel_scu_ipc_dev_iowrite8(struct intel_scu_ipc_dev * scu,u16 addr,u8 data)366f57fa185SMika Westerberg int intel_scu_ipc_dev_iowrite8(struct intel_scu_ipc_dev *scu, u16 addr, u8 data)
3679a58a333SSreedhara DS {
368f57fa185SMika Westerberg 	return pwr_reg_rdwr(scu, &addr, &data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
3699a58a333SSreedhara DS }
370f57fa185SMika Westerberg EXPORT_SYMBOL(intel_scu_ipc_dev_iowrite8);
3719a58a333SSreedhara DS 
3729a58a333SSreedhara DS /**
373f57fa185SMika Westerberg  * intel_scu_ipc_dev_readv() - Read a set of registers
374f57fa185SMika Westerberg  * @scu: Optional SCU IPC instance
3758b236565SMika Westerberg  * @addr: Register list
3768b236565SMika Westerberg  * @data: Bytes to return
3778b236565SMika Westerberg  * @len: Length of array
3789a58a333SSreedhara DS  *
3798b236565SMika Westerberg  * Read registers. Returns %0 on success or an error code. All locking
3808b236565SMika Westerberg  * between SCU accesses is handled for the caller.
3819a58a333SSreedhara DS  *
3829a58a333SSreedhara DS  * The largest array length permitted by the hardware is 5 items.
3839a58a333SSreedhara DS  *
3849a58a333SSreedhara DS  * This function may sleep.
3859a58a333SSreedhara DS  */
intel_scu_ipc_dev_readv(struct intel_scu_ipc_dev * scu,u16 * addr,u8 * data,size_t len)386f57fa185SMika Westerberg int intel_scu_ipc_dev_readv(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data,
387f57fa185SMika Westerberg 			    size_t len)
3889a58a333SSreedhara DS {
389f57fa185SMika Westerberg 	return pwr_reg_rdwr(scu, addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
3909a58a333SSreedhara DS }
391f57fa185SMika Westerberg EXPORT_SYMBOL(intel_scu_ipc_dev_readv);
3929a58a333SSreedhara DS 
3939a58a333SSreedhara DS /**
394f57fa185SMika Westerberg  * intel_scu_ipc_dev_writev() - Write a set of registers
395f57fa185SMika Westerberg  * @scu: Optional SCU IPC instance
3968b236565SMika Westerberg  * @addr: Register list
3978b236565SMika Westerberg  * @data: Bytes to write
3988b236565SMika Westerberg  * @len: Length of array
3999a58a333SSreedhara DS  *
4008b236565SMika Westerberg  * Write registers. Returns %0 on success or an error code. All locking
4018b236565SMika Westerberg  * between SCU accesses is handled for the caller.
4029a58a333SSreedhara DS  *
4039a58a333SSreedhara DS  * The largest array length permitted by the hardware is 5 items.
4049a58a333SSreedhara DS  *
4059a58a333SSreedhara DS  * This function may sleep.
4069a58a333SSreedhara DS  */
intel_scu_ipc_dev_writev(struct intel_scu_ipc_dev * scu,u16 * addr,u8 * data,size_t len)407f57fa185SMika Westerberg int intel_scu_ipc_dev_writev(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data,
408f57fa185SMika Westerberg 			     size_t len)
4099a58a333SSreedhara DS {
410f57fa185SMika Westerberg 	return pwr_reg_rdwr(scu, addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
4119a58a333SSreedhara DS }
412f57fa185SMika Westerberg EXPORT_SYMBOL(intel_scu_ipc_dev_writev);
4139a58a333SSreedhara DS 
4149a58a333SSreedhara DS /**
415f57fa185SMika Westerberg  * intel_scu_ipc_dev_update() - Update a register
416f57fa185SMika Westerberg  * @scu: Optional SCU IPC instance
4178b236565SMika Westerberg  * @addr: Register address
418f57fa185SMika Westerberg  * @data: Bits to update
4198b236565SMika Westerberg  * @mask: Mask of bits to update
4209a58a333SSreedhara DS  *
4219a58a333SSreedhara DS  * Read-modify-write power control unit register. The first data argument
4228b236565SMika Westerberg  * must be register value and second is mask value mask is a bitmap that
4238b236565SMika Westerberg  * indicates which bits to update. %0 = masked. Don't modify this bit, %1 =
4248b236565SMika Westerberg  * modify this bit. returns %0 on success or an error code.
4259a58a333SSreedhara DS  *
4269a58a333SSreedhara DS  * This function may sleep. Locking between SCU accesses is handled
4279a58a333SSreedhara DS  * for the caller.
4289a58a333SSreedhara DS  */
intel_scu_ipc_dev_update(struct intel_scu_ipc_dev * scu,u16 addr,u8 data,u8 mask)429f57fa185SMika Westerberg int intel_scu_ipc_dev_update(struct intel_scu_ipc_dev *scu, u16 addr, u8 data,
430f57fa185SMika Westerberg 			     u8 mask)
4319a58a333SSreedhara DS {
432f57fa185SMika Westerberg 	u8 tmp[2] = { data, mask };
433f57fa185SMika Westerberg 	return pwr_reg_rdwr(scu, &addr, tmp, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_M);
4349a58a333SSreedhara DS }
435f57fa185SMika Westerberg EXPORT_SYMBOL(intel_scu_ipc_dev_update);
4369a58a333SSreedhara DS 
4379a58a333SSreedhara DS /**
438f57fa185SMika Westerberg  * intel_scu_ipc_dev_simple_command() - Send a simple command
439f57fa185SMika Westerberg  * @scu: Optional SCU IPC instance
4408b236565SMika Westerberg  * @cmd: Command
4418b236565SMika Westerberg  * @sub: Sub type
4429a58a333SSreedhara DS  *
4438b236565SMika Westerberg  * Issue a simple command to the SCU. Do not use this interface if you must
4448b236565SMika Westerberg  * then access data as any data values may be overwritten by another SCU
4458b236565SMika Westerberg  * access by the time this function returns.
4469a58a333SSreedhara DS  *
4478b236565SMika Westerberg  * This function may sleep. Locking for SCU accesses is handled for the
4488b236565SMika Westerberg  * caller.
4499a58a333SSreedhara DS  */
intel_scu_ipc_dev_simple_command(struct intel_scu_ipc_dev * scu,int cmd,int sub)450f57fa185SMika Westerberg int intel_scu_ipc_dev_simple_command(struct intel_scu_ipc_dev *scu, int cmd,
451f57fa185SMika Westerberg 				     int sub)
4529a58a333SSreedhara DS {
453ea608f25SMika Westerberg 	u32 cmdval;
454ecb5646cSAxel Lin 	int err;
4559a58a333SSreedhara DS 
4569a58a333SSreedhara DS 	mutex_lock(&ipclock);
457*85e654c9SStephen Boyd 	scu = intel_scu_ipc_get(scu);
458*85e654c9SStephen Boyd 	if (IS_ERR(scu)) {
4599a58a333SSreedhara DS 		mutex_unlock(&ipclock);
460*85e654c9SStephen Boyd 		return PTR_ERR(scu);
4619a58a333SSreedhara DS 	}
462*85e654c9SStephen Boyd 
463ea608f25SMika Westerberg 	cmdval = sub << 12 | cmd;
464ea608f25SMika Westerberg 	ipc_command(scu, cmdval);
465b0b3f578SAndy Shevchenko 	err = intel_scu_ipc_check_status(scu);
4669a58a333SSreedhara DS 	mutex_unlock(&ipclock);
467ea608f25SMika Westerberg 	if (err)
468ea608f25SMika Westerberg 		dev_err(&scu->dev, "IPC command %#x failed with %d\n", cmdval, err);
4699a58a333SSreedhara DS 	return err;
4709a58a333SSreedhara DS }
471f57fa185SMika Westerberg EXPORT_SYMBOL(intel_scu_ipc_dev_simple_command);
4729a58a333SSreedhara DS 
4739a58a333SSreedhara DS /**
474b38d4ef1SAndy Shevchenko  * intel_scu_ipc_dev_command_with_size() - Command with data
475f57fa185SMika Westerberg  * @scu: Optional SCU IPC instance
4768b236565SMika Westerberg  * @cmd: Command
4778b236565SMika Westerberg  * @sub: Sub type
4788b236565SMika Westerberg  * @in: Input data
479f57fa185SMika Westerberg  * @inlen: Input length in bytes
480f57fa185SMika Westerberg  * @size: Input size written to the IPC command register in whatever
481f57fa185SMika Westerberg  *	  units (dword, byte) the particular firmware requires. Normally
482f57fa185SMika Westerberg  *	  should be the same as @inlen.
4838b236565SMika Westerberg  * @out: Output data
484f57fa185SMika Westerberg  * @outlen: Output length in bytes
4859a58a333SSreedhara DS  *
4869a58a333SSreedhara DS  * Issue a command to the SCU which involves data transfers. Do the
4878b236565SMika Westerberg  * data copies under the lock but leave it for the caller to interpret.
4889a58a333SSreedhara DS  */
intel_scu_ipc_dev_command_with_size(struct intel_scu_ipc_dev * scu,int cmd,int sub,const void * in,size_t inlen,size_t size,void * out,size_t outlen)489f57fa185SMika Westerberg int intel_scu_ipc_dev_command_with_size(struct intel_scu_ipc_dev *scu, int cmd,
490f57fa185SMika Westerberg 					int sub, const void *in, size_t inlen,
491f57fa185SMika Westerberg 					size_t size, void *out, size_t outlen)
4929a58a333SSreedhara DS {
493f57fa185SMika Westerberg 	size_t outbuflen = DIV_ROUND_UP(outlen, sizeof(u32));
494f57fa185SMika Westerberg 	size_t inbuflen = DIV_ROUND_UP(inlen, sizeof(u32));
495f57fa185SMika Westerberg 	u32 cmdval, inbuf[4] = {};
496ecb5646cSAxel Lin 	int i, err;
4979a58a333SSreedhara DS 
498f57fa185SMika Westerberg 	if (inbuflen > 4 || outbuflen > 4)
499f57fa185SMika Westerberg 		return -EINVAL;
500f57fa185SMika Westerberg 
5019a58a333SSreedhara DS 	mutex_lock(&ipclock);
502*85e654c9SStephen Boyd 	scu = intel_scu_ipc_get(scu);
503*85e654c9SStephen Boyd 	if (IS_ERR(scu)) {
5049a58a333SSreedhara DS 		mutex_unlock(&ipclock);
505*85e654c9SStephen Boyd 		return PTR_ERR(scu);
5069a58a333SSreedhara DS 	}
5079a58a333SSreedhara DS 
508f57fa185SMika Westerberg 	memcpy(inbuf, in, inlen);
509f57fa185SMika Westerberg 	for (i = 0; i < inbuflen; i++)
510f57fa185SMika Westerberg 		ipc_data_writel(scu, inbuf[i], 4 * i);
5119a58a333SSreedhara DS 
512f57fa185SMika Westerberg 	cmdval = (size << 16) | (sub << 12) | cmd;
513ea608f25SMika Westerberg 	ipc_command(scu, cmdval);
514b0b3f578SAndy Shevchenko 	err = intel_scu_ipc_check_status(scu);
5159a58a333SSreedhara DS 
516c7094d1dSKuppuswamy Sathyanarayanan 	if (!err) {
517f57fa185SMika Westerberg 		u32 outbuf[4] = {};
518f57fa185SMika Westerberg 
519f57fa185SMika Westerberg 		for (i = 0; i < outbuflen; i++)
520f57fa185SMika Westerberg 			outbuf[i] = ipc_data_readl(scu, 4 * i);
521f57fa185SMika Westerberg 
522f57fa185SMika Westerberg 		memcpy(out, outbuf, outlen);
523c7094d1dSKuppuswamy Sathyanarayanan 	}
5249a58a333SSreedhara DS 
5259a58a333SSreedhara DS 	mutex_unlock(&ipclock);
526ea608f25SMika Westerberg 	if (err)
527ea608f25SMika Westerberg 		dev_err(&scu->dev, "IPC command %#x failed with %d\n", cmdval, err);
5289a58a333SSreedhara DS 	return err;
5299a58a333SSreedhara DS }
530f57fa185SMika Westerberg EXPORT_SYMBOL(intel_scu_ipc_dev_command_with_size);
5319a58a333SSreedhara DS 
5329a58a333SSreedhara DS /*
5339a58a333SSreedhara DS  * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
5349a58a333SSreedhara DS  * When ioc bit is set to 1, caller api must wait for interrupt handler called
5359a58a333SSreedhara DS  * which in turn unlocks the caller api. Currently this is not used
5369a58a333SSreedhara DS  *
5379a58a333SSreedhara DS  * This is edge triggered so we need take no action to clear anything
5389a58a333SSreedhara DS  */
ioc(int irq,void * dev_id)5399a58a333SSreedhara DS static irqreturn_t ioc(int irq, void *dev_id)
5409a58a333SSreedhara DS {
541b0b3f578SAndy Shevchenko 	struct intel_scu_ipc_dev *scu = dev_id;
542e48b72a5SMika Westerberg 	int status = ipc_read_status(scu);
543b0b3f578SAndy Shevchenko 
544e48b72a5SMika Westerberg 	writel(status | IPC_STATUS_IRQ, scu->ipc_base + IPC_STATUS);
545b0b3f578SAndy Shevchenko 	complete(&scu->cmd_complete);
546ed12f295SKuppuswamy Sathyanarayanan 
5479a58a333SSreedhara DS 	return IRQ_HANDLED;
5489a58a333SSreedhara DS }
5499a58a333SSreedhara DS 
intel_scu_ipc_release(struct device * dev)55054b34aa0SMika Westerberg static void intel_scu_ipc_release(struct device *dev)
5519a58a333SSreedhara DS {
55254b34aa0SMika Westerberg 	struct intel_scu_ipc_dev *scu;
5539a58a333SSreedhara DS 
55454b34aa0SMika Westerberg 	scu = container_of(dev, struct intel_scu_ipc_dev, dev);
55554b34aa0SMika Westerberg 	if (scu->irq > 0)
55654b34aa0SMika Westerberg 		free_irq(scu->irq, scu);
55754b34aa0SMika Westerberg 	iounmap(scu->ipc_base);
55854b34aa0SMika Westerberg 	release_mem_region(scu->mem.start, resource_size(&scu->mem));
55954b34aa0SMika Westerberg 	kfree(scu);
5609a58a333SSreedhara DS }
5619a58a333SSreedhara DS 
56254b34aa0SMika Westerberg /**
563f57fa185SMika Westerberg  * __intel_scu_ipc_register() - Register SCU IPC device
56454b34aa0SMika Westerberg  * @parent: Parent device
56554b34aa0SMika Westerberg  * @scu_data: Data used to configure SCU IPC
566f57fa185SMika Westerberg  * @owner: Module registering the SCU IPC device
56754b34aa0SMika Westerberg  *
56854b34aa0SMika Westerberg  * Call this function to register SCU IPC mechanism under @parent.
56954b34aa0SMika Westerberg  * Returns pointer to the new SCU IPC device or ERR_PTR() in case of
570f57fa185SMika Westerberg  * failure. The caller may use the returned instance if it needs to do
571f57fa185SMika Westerberg  * SCU IPC calls itself.
57254b34aa0SMika Westerberg  */
57354b34aa0SMika Westerberg struct intel_scu_ipc_dev *
__intel_scu_ipc_register(struct device * parent,const struct intel_scu_ipc_data * scu_data,struct module * owner)574f57fa185SMika Westerberg __intel_scu_ipc_register(struct device *parent,
575f57fa185SMika Westerberg 			 const struct intel_scu_ipc_data *scu_data,
576f57fa185SMika Westerberg 			 struct module *owner)
57754b34aa0SMika Westerberg {
57854b34aa0SMika Westerberg 	int err;
57954b34aa0SMika Westerberg 	struct intel_scu_ipc_dev *scu;
58054b34aa0SMika Westerberg 	void __iomem *ipc_base;
5819a58a333SSreedhara DS 
58254b34aa0SMika Westerberg 	mutex_lock(&ipclock);
58354b34aa0SMika Westerberg 	/* We support only one IPC */
58454b34aa0SMika Westerberg 	if (ipcdev) {
58554b34aa0SMika Westerberg 		err = -EBUSY;
58654b34aa0SMika Westerberg 		goto err_unlock;
58754b34aa0SMika Westerberg 	}
58854b34aa0SMika Westerberg 
58954b34aa0SMika Westerberg 	scu = kzalloc(sizeof(*scu), GFP_KERNEL);
59054b34aa0SMika Westerberg 	if (!scu) {
59154b34aa0SMika Westerberg 		err = -ENOMEM;
59254b34aa0SMika Westerberg 		goto err_unlock;
59354b34aa0SMika Westerberg 	}
59454b34aa0SMika Westerberg 
595f57fa185SMika Westerberg 	scu->owner = owner;
59654b34aa0SMika Westerberg 	scu->dev.parent = parent;
59754b34aa0SMika Westerberg 	scu->dev.class = &intel_scu_ipc_class;
59854b34aa0SMika Westerberg 	scu->dev.release = intel_scu_ipc_release;
59954b34aa0SMika Westerberg 
60054b34aa0SMika Westerberg 	if (!request_mem_region(scu_data->mem.start, resource_size(&scu_data->mem),
60154b34aa0SMika Westerberg 				"intel_scu_ipc")) {
60254b34aa0SMika Westerberg 		err = -EBUSY;
60354b34aa0SMika Westerberg 		goto err_free;
60454b34aa0SMika Westerberg 	}
60554b34aa0SMika Westerberg 
60654b34aa0SMika Westerberg 	ipc_base = ioremap(scu_data->mem.start, resource_size(&scu_data->mem));
60754b34aa0SMika Westerberg 	if (!ipc_base) {
60854b34aa0SMika Westerberg 		err = -ENOMEM;
60954b34aa0SMika Westerberg 		goto err_release;
61054b34aa0SMika Westerberg 	}
61154b34aa0SMika Westerberg 
61254b34aa0SMika Westerberg 	scu->ipc_base = ipc_base;
61354b34aa0SMika Westerberg 	scu->mem = scu_data->mem;
61454b34aa0SMika Westerberg 	scu->irq = scu_data->irq;
61554b34aa0SMika Westerberg 	init_completion(&scu->cmd_complete);
61654b34aa0SMika Westerberg 
61754b34aa0SMika Westerberg 	if (scu->irq > 0) {
61854b34aa0SMika Westerberg 		err = request_irq(scu->irq, ioc, 0, "intel_scu_ipc", scu);
61954b34aa0SMika Westerberg 		if (err)
62054b34aa0SMika Westerberg 			goto err_unmap;
62154b34aa0SMika Westerberg 	}
62254b34aa0SMika Westerberg 
62354b34aa0SMika Westerberg 	/*
62454b34aa0SMika Westerberg 	 * After this point intel_scu_ipc_release() takes care of
62554b34aa0SMika Westerberg 	 * releasing the SCU IPC resources once refcount drops to zero.
62654b34aa0SMika Westerberg 	 */
6270b3d0cb7SYang Yingliang 	dev_set_name(&scu->dev, "intel_scu_ipc");
62854b34aa0SMika Westerberg 	err = device_register(&scu->dev);
62954b34aa0SMika Westerberg 	if (err) {
63054b34aa0SMika Westerberg 		put_device(&scu->dev);
63154b34aa0SMika Westerberg 		goto err_unlock;
63254b34aa0SMika Westerberg 	}
63354b34aa0SMika Westerberg 
63454b34aa0SMika Westerberg 	/* Assign device at last */
63554b34aa0SMika Westerberg 	ipcdev = scu;
63654b34aa0SMika Westerberg 	mutex_unlock(&ipclock);
63754b34aa0SMika Westerberg 
63854b34aa0SMika Westerberg 	return scu;
63954b34aa0SMika Westerberg 
64054b34aa0SMika Westerberg err_unmap:
64154b34aa0SMika Westerberg 	iounmap(ipc_base);
64254b34aa0SMika Westerberg err_release:
64354b34aa0SMika Westerberg 	release_mem_region(scu_data->mem.start, resource_size(&scu_data->mem));
64454b34aa0SMika Westerberg err_free:
64554b34aa0SMika Westerberg 	kfree(scu);
64654b34aa0SMika Westerberg err_unlock:
64754b34aa0SMika Westerberg 	mutex_unlock(&ipclock);
64854b34aa0SMika Westerberg 
64954b34aa0SMika Westerberg 	return ERR_PTR(err);
65054b34aa0SMika Westerberg }
651f57fa185SMika Westerberg EXPORT_SYMBOL_GPL(__intel_scu_ipc_register);
65254b34aa0SMika Westerberg 
6537e18c89dSMika Westerberg /**
6547e18c89dSMika Westerberg  * intel_scu_ipc_unregister() - Unregister SCU IPC
6557e18c89dSMika Westerberg  * @scu: SCU IPC handle
6567e18c89dSMika Westerberg  *
6577e18c89dSMika Westerberg  * This unregisters the SCU IPC device and releases the acquired
6587e18c89dSMika Westerberg  * resources once the refcount goes to zero.
6597e18c89dSMika Westerberg  */
intel_scu_ipc_unregister(struct intel_scu_ipc_dev * scu)6607e18c89dSMika Westerberg void intel_scu_ipc_unregister(struct intel_scu_ipc_dev *scu)
6617e18c89dSMika Westerberg {
6627e18c89dSMika Westerberg 	mutex_lock(&ipclock);
6637e18c89dSMika Westerberg 	if (!WARN_ON(!ipcdev)) {
6647e18c89dSMika Westerberg 		ipcdev = NULL;
6657e18c89dSMika Westerberg 		device_unregister(&scu->dev);
6667e18c89dSMika Westerberg 	}
6677e18c89dSMika Westerberg 	mutex_unlock(&ipclock);
6687e18c89dSMika Westerberg }
6697e18c89dSMika Westerberg EXPORT_SYMBOL_GPL(intel_scu_ipc_unregister);
6707e18c89dSMika Westerberg 
devm_intel_scu_ipc_unregister(struct device * dev,void * res)6717e18c89dSMika Westerberg static void devm_intel_scu_ipc_unregister(struct device *dev, void *res)
6727e18c89dSMika Westerberg {
6737e18c89dSMika Westerberg 	struct intel_scu_ipc_devres *dr = res;
6747e18c89dSMika Westerberg 	struct intel_scu_ipc_dev *scu = dr->scu;
6757e18c89dSMika Westerberg 
6767e18c89dSMika Westerberg 	intel_scu_ipc_unregister(scu);
6777e18c89dSMika Westerberg }
6787e18c89dSMika Westerberg 
6797e18c89dSMika Westerberg /**
6807e18c89dSMika Westerberg  * __devm_intel_scu_ipc_register() - Register managed SCU IPC device
6817e18c89dSMika Westerberg  * @parent: Parent device
6827e18c89dSMika Westerberg  * @scu_data: Data used to configure SCU IPC
6837e18c89dSMika Westerberg  * @owner: Module registering the SCU IPC device
6847e18c89dSMika Westerberg  *
6857e18c89dSMika Westerberg  * Call this function to register managed SCU IPC mechanism under
6867e18c89dSMika Westerberg  * @parent. Returns pointer to the new SCU IPC device or ERR_PTR() in
6877e18c89dSMika Westerberg  * case of failure. The caller may use the returned instance if it needs
6887e18c89dSMika Westerberg  * to do SCU IPC calls itself.
6897e18c89dSMika Westerberg  */
6907e18c89dSMika Westerberg struct intel_scu_ipc_dev *
__devm_intel_scu_ipc_register(struct device * parent,const struct intel_scu_ipc_data * scu_data,struct module * owner)6917e18c89dSMika Westerberg __devm_intel_scu_ipc_register(struct device *parent,
6927e18c89dSMika Westerberg 			      const struct intel_scu_ipc_data *scu_data,
6937e18c89dSMika Westerberg 			      struct module *owner)
6947e18c89dSMika Westerberg {
6957e18c89dSMika Westerberg 	struct intel_scu_ipc_devres *dr;
6967e18c89dSMika Westerberg 	struct intel_scu_ipc_dev *scu;
6977e18c89dSMika Westerberg 
6987e18c89dSMika Westerberg 	dr = devres_alloc(devm_intel_scu_ipc_unregister, sizeof(*dr), GFP_KERNEL);
6997e18c89dSMika Westerberg 	if (!dr)
7007e18c89dSMika Westerberg 		return NULL;
7017e18c89dSMika Westerberg 
7027e18c89dSMika Westerberg 	scu = __intel_scu_ipc_register(parent, scu_data, owner);
7037e18c89dSMika Westerberg 	if (IS_ERR(scu)) {
7047e18c89dSMika Westerberg 		devres_free(dr);
7057e18c89dSMika Westerberg 		return scu;
7067e18c89dSMika Westerberg 	}
7077e18c89dSMika Westerberg 
7087e18c89dSMika Westerberg 	dr->scu = scu;
7097e18c89dSMika Westerberg 	devres_add(parent, dr);
7107e18c89dSMika Westerberg 
7117e18c89dSMika Westerberg 	return scu;
7127e18c89dSMika Westerberg }
7137e18c89dSMika Westerberg EXPORT_SYMBOL_GPL(__devm_intel_scu_ipc_register);
7147e18c89dSMika Westerberg 
intel_scu_ipc_init(void)71554b34aa0SMika Westerberg static int __init intel_scu_ipc_init(void)
71654b34aa0SMika Westerberg {
71754b34aa0SMika Westerberg 	return class_register(&intel_scu_ipc_class);
71854b34aa0SMika Westerberg }
71954b34aa0SMika Westerberg subsys_initcall(intel_scu_ipc_init);
72054b34aa0SMika Westerberg 
intel_scu_ipc_exit(void)72154b34aa0SMika Westerberg static void __exit intel_scu_ipc_exit(void)
72254b34aa0SMika Westerberg {
72354b34aa0SMika Westerberg 	class_unregister(&intel_scu_ipc_class);
72454b34aa0SMika Westerberg }
72554b34aa0SMika Westerberg module_exit(intel_scu_ipc_exit);
726