18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for the Intel P-Unit Mailbox IPC mechanism 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) Copyright 2015 Intel Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * The heart of the P-Unit is the Foxton microcontroller and its firmware, 88c2ecf20Sopenharmony_ci * which provide mailbox interface for power management usage. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/bitops.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <asm/intel_punit_ipc.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* IPC Mailbox registers */ 238c2ecf20Sopenharmony_ci#define OFFSET_DATA_LOW 0x0 248c2ecf20Sopenharmony_ci#define OFFSET_DATA_HIGH 0x4 258c2ecf20Sopenharmony_ci/* bit field of interface register */ 268c2ecf20Sopenharmony_ci#define CMD_RUN BIT(31) 278c2ecf20Sopenharmony_ci#define CMD_ERRCODE_MASK GENMASK(7, 0) 288c2ecf20Sopenharmony_ci#define CMD_PARA1_SHIFT 8 298c2ecf20Sopenharmony_ci#define CMD_PARA2_SHIFT 16 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define CMD_TIMEOUT_SECONDS 1 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cienum { 348c2ecf20Sopenharmony_ci BASE_DATA = 0, 358c2ecf20Sopenharmony_ci BASE_IFACE, 368c2ecf20Sopenharmony_ci BASE_MAX, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_citypedef struct { 408c2ecf20Sopenharmony_ci struct device *dev; 418c2ecf20Sopenharmony_ci struct mutex lock; 428c2ecf20Sopenharmony_ci int irq; 438c2ecf20Sopenharmony_ci struct completion cmd_complete; 448c2ecf20Sopenharmony_ci /* base of interface and data registers */ 458c2ecf20Sopenharmony_ci void __iomem *base[RESERVED_IPC][BASE_MAX]; 468c2ecf20Sopenharmony_ci IPC_TYPE type; 478c2ecf20Sopenharmony_ci} IPC_DEV; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic IPC_DEV *punit_ipcdev; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic inline u32 ipc_read_status(IPC_DEV *ipcdev, IPC_TYPE type) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci return readl(ipcdev->base[type][BASE_IFACE]); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic inline void ipc_write_cmd(IPC_DEV *ipcdev, IPC_TYPE type, u32 cmd) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci writel(cmd, ipcdev->base[type][BASE_IFACE]); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic inline u32 ipc_read_data_low(IPC_DEV *ipcdev, IPC_TYPE type) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic inline u32 ipc_read_data_high(IPC_DEV *ipcdev, IPC_TYPE type) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic inline void ipc_write_data_low(IPC_DEV *ipcdev, IPC_TYPE type, u32 data) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic inline void ipc_write_data_high(IPC_DEV *ipcdev, IPC_TYPE type, u32 data) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic const char *ipc_err_string(int error) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci if (error == IPC_PUNIT_ERR_SUCCESS) 848c2ecf20Sopenharmony_ci return "no error"; 858c2ecf20Sopenharmony_ci else if (error == IPC_PUNIT_ERR_INVALID_CMD) 868c2ecf20Sopenharmony_ci return "invalid command"; 878c2ecf20Sopenharmony_ci else if (error == IPC_PUNIT_ERR_INVALID_PARAMETER) 888c2ecf20Sopenharmony_ci return "invalid parameter"; 898c2ecf20Sopenharmony_ci else if (error == IPC_PUNIT_ERR_CMD_TIMEOUT) 908c2ecf20Sopenharmony_ci return "command timeout"; 918c2ecf20Sopenharmony_ci else if (error == IPC_PUNIT_ERR_CMD_LOCKED) 928c2ecf20Sopenharmony_ci return "command locked"; 938c2ecf20Sopenharmony_ci else if (error == IPC_PUNIT_ERR_INVALID_VR_ID) 948c2ecf20Sopenharmony_ci return "invalid vr id"; 958c2ecf20Sopenharmony_ci else if (error == IPC_PUNIT_ERR_VR_ERR) 968c2ecf20Sopenharmony_ci return "vr error"; 978c2ecf20Sopenharmony_ci else 988c2ecf20Sopenharmony_ci return "unknown error"; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int intel_punit_ipc_check_status(IPC_DEV *ipcdev, IPC_TYPE type) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci int loops = CMD_TIMEOUT_SECONDS * USEC_PER_SEC; 1048c2ecf20Sopenharmony_ci int errcode; 1058c2ecf20Sopenharmony_ci int status; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (ipcdev->irq) { 1088c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&ipcdev->cmd_complete, 1098c2ecf20Sopenharmony_ci CMD_TIMEOUT_SECONDS * HZ)) { 1108c2ecf20Sopenharmony_ci dev_err(ipcdev->dev, "IPC timed out\n"); 1118c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci } else { 1148c2ecf20Sopenharmony_ci while ((ipc_read_status(ipcdev, type) & CMD_RUN) && --loops) 1158c2ecf20Sopenharmony_ci udelay(1); 1168c2ecf20Sopenharmony_ci if (!loops) { 1178c2ecf20Sopenharmony_ci dev_err(ipcdev->dev, "IPC timed out\n"); 1188c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci status = ipc_read_status(ipcdev, type); 1238c2ecf20Sopenharmony_ci errcode = status & CMD_ERRCODE_MASK; 1248c2ecf20Sopenharmony_ci if (errcode) { 1258c2ecf20Sopenharmony_ci dev_err(ipcdev->dev, "IPC failed: %s, IPC_STS=0x%x\n", 1268c2ecf20Sopenharmony_ci ipc_err_string(errcode), status); 1278c2ecf20Sopenharmony_ci return -EIO; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/** 1348c2ecf20Sopenharmony_ci * intel_punit_ipc_simple_command() - Simple IPC command 1358c2ecf20Sopenharmony_ci * @cmd: IPC command code. 1368c2ecf20Sopenharmony_ci * @para1: First 8bit parameter, set 0 if not used. 1378c2ecf20Sopenharmony_ci * @para2: Second 8bit parameter, set 0 if not used. 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci * Send a IPC command to P-Unit when there is no data transaction 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * Return: IPC error code or 0 on success. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ciint intel_punit_ipc_simple_command(int cmd, int para1, int para2) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci IPC_DEV *ipcdev = punit_ipcdev; 1468c2ecf20Sopenharmony_ci IPC_TYPE type; 1478c2ecf20Sopenharmony_ci u32 val; 1488c2ecf20Sopenharmony_ci int ret; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci mutex_lock(&ipcdev->lock); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci reinit_completion(&ipcdev->cmd_complete); 1538c2ecf20Sopenharmony_ci type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK; 1568c2ecf20Sopenharmony_ci val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT; 1578c2ecf20Sopenharmony_ci ipc_write_cmd(ipcdev, type, val); 1588c2ecf20Sopenharmony_ci ret = intel_punit_ipc_check_status(ipcdev, type); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci mutex_unlock(&ipcdev->lock); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return ret; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(intel_punit_ipc_simple_command); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/** 1678c2ecf20Sopenharmony_ci * intel_punit_ipc_command() - IPC command with data and pointers 1688c2ecf20Sopenharmony_ci * @cmd: IPC command code. 1698c2ecf20Sopenharmony_ci * @para1: First 8bit parameter, set 0 if not used. 1708c2ecf20Sopenharmony_ci * @para2: Second 8bit parameter, set 0 if not used. 1718c2ecf20Sopenharmony_ci * @in: Input data, 32bit for BIOS cmd, two 32bit for GTD and ISPD. 1728c2ecf20Sopenharmony_ci * @out: Output data. 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * Send a IPC command to P-Unit with data transaction 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * Return: IPC error code or 0 on success. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ciint intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci IPC_DEV *ipcdev = punit_ipcdev; 1818c2ecf20Sopenharmony_ci IPC_TYPE type; 1828c2ecf20Sopenharmony_ci u32 val; 1838c2ecf20Sopenharmony_ci int ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci mutex_lock(&ipcdev->lock); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci reinit_completion(&ipcdev->cmd_complete); 1888c2ecf20Sopenharmony_ci type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (in) { 1918c2ecf20Sopenharmony_ci ipc_write_data_low(ipcdev, type, *in); 1928c2ecf20Sopenharmony_ci if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC) 1938c2ecf20Sopenharmony_ci ipc_write_data_high(ipcdev, type, *++in); 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK; 1978c2ecf20Sopenharmony_ci val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT; 1988c2ecf20Sopenharmony_ci ipc_write_cmd(ipcdev, type, val); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci ret = intel_punit_ipc_check_status(ipcdev, type); 2018c2ecf20Sopenharmony_ci if (ret) 2028c2ecf20Sopenharmony_ci goto out; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (out) { 2058c2ecf20Sopenharmony_ci *out = ipc_read_data_low(ipcdev, type); 2068c2ecf20Sopenharmony_ci if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC) 2078c2ecf20Sopenharmony_ci *++out = ipc_read_data_high(ipcdev, type); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ciout: 2118c2ecf20Sopenharmony_ci mutex_unlock(&ipcdev->lock); 2128c2ecf20Sopenharmony_ci return ret; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_punit_ipc_command); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic irqreturn_t intel_punit_ioc(int irq, void *dev_id) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci IPC_DEV *ipcdev = dev_id; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci complete(&ipcdev->cmd_complete); 2218c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int intel_punit_get_bars(struct platform_device *pdev) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci void __iomem *addr; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* 2298c2ecf20Sopenharmony_ci * The following resources are required 2308c2ecf20Sopenharmony_ci * - BIOS_IPC BASE_DATA 2318c2ecf20Sopenharmony_ci * - BIOS_IPC BASE_IFACE 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci addr = devm_platform_ioremap_resource(pdev, 0); 2348c2ecf20Sopenharmony_ci if (IS_ERR(addr)) 2358c2ecf20Sopenharmony_ci return PTR_ERR(addr); 2368c2ecf20Sopenharmony_ci punit_ipcdev->base[BIOS_IPC][BASE_DATA] = addr; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci addr = devm_platform_ioremap_resource(pdev, 1); 2398c2ecf20Sopenharmony_ci if (IS_ERR(addr)) 2408c2ecf20Sopenharmony_ci return PTR_ERR(addr); 2418c2ecf20Sopenharmony_ci punit_ipcdev->base[BIOS_IPC][BASE_IFACE] = addr; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* 2448c2ecf20Sopenharmony_ci * The following resources are optional 2458c2ecf20Sopenharmony_ci * - ISPDRIVER_IPC BASE_DATA 2468c2ecf20Sopenharmony_ci * - ISPDRIVER_IPC BASE_IFACE 2478c2ecf20Sopenharmony_ci * - GTDRIVER_IPC BASE_DATA 2488c2ecf20Sopenharmony_ci * - GTDRIVER_IPC BASE_IFACE 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci addr = devm_platform_ioremap_resource(pdev, 2); 2518c2ecf20Sopenharmony_ci if (!IS_ERR(addr)) 2528c2ecf20Sopenharmony_ci punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci addr = devm_platform_ioremap_resource(pdev, 3); 2558c2ecf20Sopenharmony_ci if (!IS_ERR(addr)) 2568c2ecf20Sopenharmony_ci punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci addr = devm_platform_ioremap_resource(pdev, 4); 2598c2ecf20Sopenharmony_ci if (!IS_ERR(addr)) 2608c2ecf20Sopenharmony_ci punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci addr = devm_platform_ioremap_resource(pdev, 5); 2638c2ecf20Sopenharmony_ci if (!IS_ERR(addr)) 2648c2ecf20Sopenharmony_ci punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int intel_punit_ipc_probe(struct platform_device *pdev) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci int irq, ret; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci punit_ipcdev = devm_kzalloc(&pdev->dev, 2748c2ecf20Sopenharmony_ci sizeof(*punit_ipcdev), GFP_KERNEL); 2758c2ecf20Sopenharmony_ci if (!punit_ipcdev) 2768c2ecf20Sopenharmony_ci return -ENOMEM; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, punit_ipcdev); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci irq = platform_get_irq_optional(pdev, 0); 2818c2ecf20Sopenharmony_ci if (irq < 0) { 2828c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Invalid IRQ, using polling mode\n"); 2838c2ecf20Sopenharmony_ci } else { 2848c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, intel_punit_ioc, 2858c2ecf20Sopenharmony_ci IRQF_NO_SUSPEND, "intel_punit_ipc", 2868c2ecf20Sopenharmony_ci &punit_ipcdev); 2878c2ecf20Sopenharmony_ci if (ret) { 2888c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to request irq: %d\n", irq); 2898c2ecf20Sopenharmony_ci return ret; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci punit_ipcdev->irq = irq; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci ret = intel_punit_get_bars(pdev); 2958c2ecf20Sopenharmony_ci if (ret) 2968c2ecf20Sopenharmony_ci return ret; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci punit_ipcdev->dev = &pdev->dev; 2998c2ecf20Sopenharmony_ci mutex_init(&punit_ipcdev->lock); 3008c2ecf20Sopenharmony_ci init_completion(&punit_ipcdev->cmd_complete); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int intel_punit_ipc_remove(struct platform_device *pdev) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic const struct acpi_device_id punit_ipc_acpi_ids[] = { 3118c2ecf20Sopenharmony_ci { "INT34D4", 0 }, 3128c2ecf20Sopenharmony_ci { } 3138c2ecf20Sopenharmony_ci}; 3148c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, punit_ipc_acpi_ids); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic struct platform_driver intel_punit_ipc_driver = { 3178c2ecf20Sopenharmony_ci .probe = intel_punit_ipc_probe, 3188c2ecf20Sopenharmony_ci .remove = intel_punit_ipc_remove, 3198c2ecf20Sopenharmony_ci .driver = { 3208c2ecf20Sopenharmony_ci .name = "intel_punit_ipc", 3218c2ecf20Sopenharmony_ci .acpi_match_table = punit_ipc_acpi_ids, 3228c2ecf20Sopenharmony_ci }, 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int __init intel_punit_ipc_init(void) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci return platform_driver_register(&intel_punit_ipc_driver); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic void __exit intel_punit_ipc_exit(void) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci platform_driver_unregister(&intel_punit_ipc_driver); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ciMODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>"); 3368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel P-Unit IPC driver"); 3378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/* Some modules are dependent on this, so init earlier */ 3408c2ecf20Sopenharmony_cifs_initcall(intel_punit_ipc_init); 3418c2ecf20Sopenharmony_cimodule_exit(intel_punit_ipc_exit); 342