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