Loading drivers/soc/qcom/Kconfig +11 −0 Original line number Diff line number Diff line Loading @@ -519,6 +519,17 @@ config QSEE_IPC_IRQ Clients can use this driver to avoid adding common interrupt handling code. config MSM_SPSS_UTILS depends on MSM_PIL bool "Secure Processor Utilities" help spss-utils driver selects Secure Processor firmware file name. The firmware file name for dev, test or production is selected based on two fuses. Different file name is used for differnt SPSS HW versions, because the SPSS firmware size is too small to support multiple HW versions. config QSEE_IPC_IRQ_BRIDGE tristate "QSEE IPC Interrupt Bridge" select QSEE_IPC_IRQ Loading drivers/soc/qcom/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ obj-$(CONFIG_MSM_TZ_SMMU) += msm_tz_smmu.o CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) obj-$(CONFIG_QCOM_SCM) += scm.o obj-$(CONFIG_QCOM_EARLY_RANDOM) += early_random.o obj-$(CONFIG_MSM_SPSS_UTILS) += spss_utils.o obj-$(CONFIG_MSM_BOOT_STATS) += boot_stats.o obj-$(CONFIG_MSM_CORE_HANG_DETECT) += core_hang_detect.o obj-$(CONFIG_MSM_GLADIATOR_HANG_DETECT) += gladiator_hang_detect.o Loading drivers/soc/qcom/spss_utils.c 0 → 100644 +393 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ /* * Secure-Processor-SubSystem (SPSS) utilities. * * This driver provides utilities for the Secure Processor (SP). * * The SP daemon needs to load different SPSS images based on: * * 1. Test/Production key used to sign the SPSS image (read fuses). * 2. SPSS HW version (selected via Device Tree). * */ #define pr_fmt(fmt) "spss_utils [%s]: " fmt, __func__ #include <linux/kernel.h> /* min() */ #include <linux/module.h> /* MODULE_LICENSE */ #include <linux/device.h> /* class_create() */ #include <linux/slab.h> /* kzalloc() */ #include <linux/fs.h> /* file_operations */ #include <linux/cdev.h> /* cdev_add() */ #include <linux/errno.h> /* EINVAL, ETIMEDOUT */ #include <linux/printk.h> /* pr_err() */ #include <linux/bitops.h> /* BIT(x) */ #include <linux/platform_device.h> /* platform_driver_register() */ #include <linux/of.h> /* of_property_count_strings() */ #include <linux/io.h> /* ioremap_nocache() */ #include <soc/qcom/subsystem_restart.h> /* driver name */ #define DEVICE_NAME "spss-utils" enum spss_firmware_type { SPSS_FW_TYPE_DEV = 'd', SPSS_FW_TYPE_TEST = 't', SPSS_FW_TYPE_PROD = 'p', SPSS_FW_TYPE_NONE = 'z', }; static enum spss_firmware_type firmware_type = SPSS_FW_TYPE_TEST; static const char *dev_firmware_name; static const char *test_firmware_name; static const char *prod_firmware_name; static const char *none_firmware_name = "nospss"; static const char *firmware_name = "NA"; static struct device *spss_dev; static u32 spss_debug_reg_addr; /* SP_SCSR_MBn_SP2CL_GPm(n,m) */ static u32 spss_emul_type_reg_addr; /* TCSR_SOC_EMULATION_TYPE */ #define SPU_EMULATUION (BIT(0) | BIT(1)) #define SPU_PRESENT_IN_EMULATION BIT(2) /*==========================================================================*/ /* Device Sysfs */ /*==========================================================================*/ static ssize_t firmware_name_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; if (firmware_name == NULL) ret = scnprintf(buf, PAGE_SIZE, "%s\n", "unknown"); else ret = scnprintf(buf, PAGE_SIZE, "%s\n", firmware_name); return ret; } static DEVICE_ATTR_RO(firmware_name); static ssize_t test_fuse_state_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; switch (firmware_type) { case SPSS_FW_TYPE_DEV: ret = scnprintf(buf, PAGE_SIZE, "%s", "dev"); break; case SPSS_FW_TYPE_TEST: ret = scnprintf(buf, PAGE_SIZE, "%s", "test"); break; case SPSS_FW_TYPE_PROD: ret = scnprintf(buf, PAGE_SIZE, "%s", "prod"); break; default: return -EINVAL; } return ret; } static DEVICE_ATTR_RO(test_fuse_state); static ssize_t spss_debug_reg_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; void __iomem *spss_debug_reg = NULL; u32 val1, val2; pr_debug("spss_debug_reg_addr [0x%x]\n", spss_debug_reg_addr); spss_debug_reg = ioremap_nocache(spss_debug_reg_addr, sizeof(u32)*2); if (!spss_debug_reg) { pr_err("can't map debug reg addr\n"); return -EINVAL; } val1 = readl_relaxed(spss_debug_reg); val2 = readl_relaxed(((char *) spss_debug_reg) + sizeof(u32)); ret = scnprintf(buf, PAGE_SIZE, "val1 [0x%x] val2 [0x%x]\n", val1, val2); iounmap(spss_debug_reg); return ret; } static DEVICE_ATTR_RO(spss_debug_reg); static int spss_create_sysfs(struct device *dev) { int ret; ret = device_create_file(dev, &dev_attr_firmware_name); if (ret < 0) { pr_err("failed to create sysfs file for firmware_name\n"); return ret; } ret = device_create_file(dev, &dev_attr_test_fuse_state); if (ret < 0) { pr_err("failed to create sysfs file for test_fuse_state\n"); device_remove_file(dev, &dev_attr_firmware_name); return ret; } ret = device_create_file(dev, &dev_attr_spss_debug_reg); if (ret < 0) { pr_err("failed to create sysfs file for spss_debug_reg\n"); device_remove_file(dev, &dev_attr_firmware_name); device_remove_file(dev, &dev_attr_test_fuse_state); return ret; } return 0; } /*==========================================================================*/ /* Device Tree */ /*==========================================================================*/ /** * spss_parse_dt() - Parse Device Tree info. */ static int spss_parse_dt(struct device_node *node) { int ret; u32 spss_fuse1_addr = 0; u32 spss_fuse1_bit = 0; u32 spss_fuse1_mask = 0; void __iomem *spss_fuse1_reg = NULL; u32 spss_fuse2_addr = 0; u32 spss_fuse2_bit = 0; u32 spss_fuse2_mask = 0; void __iomem *spss_fuse2_reg = NULL; u32 val1 = 0; u32 val2 = 0; void __iomem *spss_emul_type_reg = NULL; u32 spss_emul_type_val = 0; ret = of_property_read_string(node, "qcom,spss-dev-firmware-name", &dev_firmware_name); if (ret < 0) { pr_err("can't get dev fw name\n"); return -EINVAL; } ret = of_property_read_string(node, "qcom,spss-test-firmware-name", &test_firmware_name); if (ret < 0) { pr_err("can't get test fw name\n"); return -EINVAL; } ret = of_property_read_string(node, "qcom,spss-prod-firmware-name", &prod_firmware_name); if (ret < 0) { pr_err("can't get prod fw name\n"); return -EINVAL; } ret = of_property_read_u32(node, "qcom,spss-fuse1-addr", &spss_fuse1_addr); if (ret < 0) { pr_err("can't get fuse1 addr\n"); return -EINVAL; } ret = of_property_read_u32(node, "qcom,spss-fuse2-addr", &spss_fuse2_addr); if (ret < 0) { pr_err("can't get fuse2 addr\n"); return -EINVAL; } ret = of_property_read_u32(node, "qcom,spss-fuse1-bit", &spss_fuse1_bit); if (ret < 0) { pr_err("can't get fuse1 bit\n"); return -EINVAL; } ret = of_property_read_u32(node, "qcom,spss-fuse2-bit", &spss_fuse2_bit); if (ret < 0) { pr_err("can't get fuse2 bit\n"); return -EINVAL; } spss_fuse1_mask = BIT(spss_fuse1_bit); spss_fuse2_mask = BIT(spss_fuse2_bit); pr_debug("spss fuse1 addr [0x%x] bit [%d]\n", (int) spss_fuse1_addr, (int) spss_fuse1_bit); pr_debug("spss fuse2 addr [0x%x] bit [%d]\n", (int) spss_fuse2_addr, (int) spss_fuse2_bit); spss_fuse1_reg = ioremap_nocache(spss_fuse1_addr, sizeof(u32)); if (!spss_fuse1_reg) { pr_err("can't map fuse1 addr\n"); return -EINVAL; } spss_fuse2_reg = ioremap_nocache(spss_fuse2_addr, sizeof(u32)); if (!spss_fuse2_reg) { iounmap(spss_fuse1_reg); pr_err("can't map fuse2 addr\n"); return -EINVAL; } val1 = readl_relaxed(spss_fuse1_reg); val2 = readl_relaxed(spss_fuse2_reg); pr_debug("spss fuse1 value [0x%08x]\n", (int) val1); pr_debug("spss fuse2 value [0x%08x]\n", (int) val2); pr_debug("spss fuse1 mask [0x%08x]\n", (int) spss_fuse1_mask); pr_debug("spss fuse2 mask [0x%08x]\n", (int) spss_fuse2_mask); /** * Set firmware_type based on fuses: * SPSS_CONFIG_MODE 11: dev * SPSS_CONFIG_MODE 01 or 10: test * SPSS_CONFIG_MODE 00: prod */ if ((val1 & spss_fuse1_mask) && (val2 & spss_fuse2_mask)) firmware_type = SPSS_FW_TYPE_DEV; else if ((val1 & spss_fuse1_mask) || (val2 & spss_fuse2_mask)) firmware_type = SPSS_FW_TYPE_TEST; else firmware_type = SPSS_FW_TYPE_PROD; iounmap(spss_fuse1_reg); iounmap(spss_fuse2_reg); ret = of_property_read_u32(node, "qcom,spss-debug-reg-addr", &spss_debug_reg_addr); if (ret < 0) { pr_err("can't get debug regs addr\n"); return ret; } ret = of_property_read_u32(node, "qcom,spss-emul-type-reg-addr", &spss_emul_type_reg_addr); if (ret < 0) { pr_err("can't get spss-emulation-type-reg addr\n"); return -EINVAL; } spss_emul_type_reg = ioremap_nocache(spss_emul_type_reg_addr, sizeof(u32)); if (!spss_emul_type_reg) { pr_err("can't map soc-emulation-type reg addr\n"); return -EINVAL; } spss_emul_type_val = readl_relaxed(spss_emul_type_reg); pr_debug("spss_emul_type value [0x%08x]\n", (int)spss_emul_type_val); if ((spss_emul_type_val & SPU_EMULATUION) && !(spss_emul_type_val & SPU_PRESENT_IN_EMULATION)) { /* for some emulation platforms SPSS is not present */ firmware_type = SPSS_FW_TYPE_NONE; } iounmap(spss_emul_type_reg); return 0; } /** * spss_probe() - initialization sequence */ static int spss_probe(struct platform_device *pdev) { int ret = 0; struct device_node *np = NULL; struct device *dev = NULL; np = pdev->dev.of_node; dev = &pdev->dev; spss_dev = dev; platform_set_drvdata(pdev, dev); ret = spss_parse_dt(np); if (ret < 0) return ret; switch (firmware_type) { case SPSS_FW_TYPE_DEV: firmware_name = dev_firmware_name; break; case SPSS_FW_TYPE_TEST: firmware_name = test_firmware_name; break; case SPSS_FW_TYPE_PROD: firmware_name = prod_firmware_name; break; case SPSS_FW_TYPE_NONE: firmware_name = none_firmware_name; break; default: return -EINVAL; } ret = subsystem_set_fwname("spss", firmware_name); if (ret < 0) { pr_err("fail to set fw name\n"); return -EINVAL; } ret = spss_create_sysfs(dev); if (ret < 0) return ret; return 0; } static const struct of_device_id spss_match_table[] = { { .compatible = "qcom,spss-utils", }, { }, }; static struct platform_driver spss_driver = { .probe = spss_probe, .driver = { .name = DEVICE_NAME, .of_match_table = of_match_ptr(spss_match_table), }, }; /*==========================================================================*/ /* Driver Init/Exit */ /*==========================================================================*/ static int __init spss_init(void) { int ret = 0; ret = platform_driver_register(&spss_driver); if (ret) pr_err("register platform driver failed, ret [%d]\n", ret); return ret; } late_initcall(spss_init); /* start after PIL driver */ MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Secure Processor Utilities"); Loading
drivers/soc/qcom/Kconfig +11 −0 Original line number Diff line number Diff line Loading @@ -519,6 +519,17 @@ config QSEE_IPC_IRQ Clients can use this driver to avoid adding common interrupt handling code. config MSM_SPSS_UTILS depends on MSM_PIL bool "Secure Processor Utilities" help spss-utils driver selects Secure Processor firmware file name. The firmware file name for dev, test or production is selected based on two fuses. Different file name is used for differnt SPSS HW versions, because the SPSS firmware size is too small to support multiple HW versions. config QSEE_IPC_IRQ_BRIDGE tristate "QSEE IPC Interrupt Bridge" select QSEE_IPC_IRQ Loading
drivers/soc/qcom/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ obj-$(CONFIG_MSM_TZ_SMMU) += msm_tz_smmu.o CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) obj-$(CONFIG_QCOM_SCM) += scm.o obj-$(CONFIG_QCOM_EARLY_RANDOM) += early_random.o obj-$(CONFIG_MSM_SPSS_UTILS) += spss_utils.o obj-$(CONFIG_MSM_BOOT_STATS) += boot_stats.o obj-$(CONFIG_MSM_CORE_HANG_DETECT) += core_hang_detect.o obj-$(CONFIG_MSM_GLADIATOR_HANG_DETECT) += gladiator_hang_detect.o Loading
drivers/soc/qcom/spss_utils.c 0 → 100644 +393 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ /* * Secure-Processor-SubSystem (SPSS) utilities. * * This driver provides utilities for the Secure Processor (SP). * * The SP daemon needs to load different SPSS images based on: * * 1. Test/Production key used to sign the SPSS image (read fuses). * 2. SPSS HW version (selected via Device Tree). * */ #define pr_fmt(fmt) "spss_utils [%s]: " fmt, __func__ #include <linux/kernel.h> /* min() */ #include <linux/module.h> /* MODULE_LICENSE */ #include <linux/device.h> /* class_create() */ #include <linux/slab.h> /* kzalloc() */ #include <linux/fs.h> /* file_operations */ #include <linux/cdev.h> /* cdev_add() */ #include <linux/errno.h> /* EINVAL, ETIMEDOUT */ #include <linux/printk.h> /* pr_err() */ #include <linux/bitops.h> /* BIT(x) */ #include <linux/platform_device.h> /* platform_driver_register() */ #include <linux/of.h> /* of_property_count_strings() */ #include <linux/io.h> /* ioremap_nocache() */ #include <soc/qcom/subsystem_restart.h> /* driver name */ #define DEVICE_NAME "spss-utils" enum spss_firmware_type { SPSS_FW_TYPE_DEV = 'd', SPSS_FW_TYPE_TEST = 't', SPSS_FW_TYPE_PROD = 'p', SPSS_FW_TYPE_NONE = 'z', }; static enum spss_firmware_type firmware_type = SPSS_FW_TYPE_TEST; static const char *dev_firmware_name; static const char *test_firmware_name; static const char *prod_firmware_name; static const char *none_firmware_name = "nospss"; static const char *firmware_name = "NA"; static struct device *spss_dev; static u32 spss_debug_reg_addr; /* SP_SCSR_MBn_SP2CL_GPm(n,m) */ static u32 spss_emul_type_reg_addr; /* TCSR_SOC_EMULATION_TYPE */ #define SPU_EMULATUION (BIT(0) | BIT(1)) #define SPU_PRESENT_IN_EMULATION BIT(2) /*==========================================================================*/ /* Device Sysfs */ /*==========================================================================*/ static ssize_t firmware_name_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; if (firmware_name == NULL) ret = scnprintf(buf, PAGE_SIZE, "%s\n", "unknown"); else ret = scnprintf(buf, PAGE_SIZE, "%s\n", firmware_name); return ret; } static DEVICE_ATTR_RO(firmware_name); static ssize_t test_fuse_state_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; switch (firmware_type) { case SPSS_FW_TYPE_DEV: ret = scnprintf(buf, PAGE_SIZE, "%s", "dev"); break; case SPSS_FW_TYPE_TEST: ret = scnprintf(buf, PAGE_SIZE, "%s", "test"); break; case SPSS_FW_TYPE_PROD: ret = scnprintf(buf, PAGE_SIZE, "%s", "prod"); break; default: return -EINVAL; } return ret; } static DEVICE_ATTR_RO(test_fuse_state); static ssize_t spss_debug_reg_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; void __iomem *spss_debug_reg = NULL; u32 val1, val2; pr_debug("spss_debug_reg_addr [0x%x]\n", spss_debug_reg_addr); spss_debug_reg = ioremap_nocache(spss_debug_reg_addr, sizeof(u32)*2); if (!spss_debug_reg) { pr_err("can't map debug reg addr\n"); return -EINVAL; } val1 = readl_relaxed(spss_debug_reg); val2 = readl_relaxed(((char *) spss_debug_reg) + sizeof(u32)); ret = scnprintf(buf, PAGE_SIZE, "val1 [0x%x] val2 [0x%x]\n", val1, val2); iounmap(spss_debug_reg); return ret; } static DEVICE_ATTR_RO(spss_debug_reg); static int spss_create_sysfs(struct device *dev) { int ret; ret = device_create_file(dev, &dev_attr_firmware_name); if (ret < 0) { pr_err("failed to create sysfs file for firmware_name\n"); return ret; } ret = device_create_file(dev, &dev_attr_test_fuse_state); if (ret < 0) { pr_err("failed to create sysfs file for test_fuse_state\n"); device_remove_file(dev, &dev_attr_firmware_name); return ret; } ret = device_create_file(dev, &dev_attr_spss_debug_reg); if (ret < 0) { pr_err("failed to create sysfs file for spss_debug_reg\n"); device_remove_file(dev, &dev_attr_firmware_name); device_remove_file(dev, &dev_attr_test_fuse_state); return ret; } return 0; } /*==========================================================================*/ /* Device Tree */ /*==========================================================================*/ /** * spss_parse_dt() - Parse Device Tree info. */ static int spss_parse_dt(struct device_node *node) { int ret; u32 spss_fuse1_addr = 0; u32 spss_fuse1_bit = 0; u32 spss_fuse1_mask = 0; void __iomem *spss_fuse1_reg = NULL; u32 spss_fuse2_addr = 0; u32 spss_fuse2_bit = 0; u32 spss_fuse2_mask = 0; void __iomem *spss_fuse2_reg = NULL; u32 val1 = 0; u32 val2 = 0; void __iomem *spss_emul_type_reg = NULL; u32 spss_emul_type_val = 0; ret = of_property_read_string(node, "qcom,spss-dev-firmware-name", &dev_firmware_name); if (ret < 0) { pr_err("can't get dev fw name\n"); return -EINVAL; } ret = of_property_read_string(node, "qcom,spss-test-firmware-name", &test_firmware_name); if (ret < 0) { pr_err("can't get test fw name\n"); return -EINVAL; } ret = of_property_read_string(node, "qcom,spss-prod-firmware-name", &prod_firmware_name); if (ret < 0) { pr_err("can't get prod fw name\n"); return -EINVAL; } ret = of_property_read_u32(node, "qcom,spss-fuse1-addr", &spss_fuse1_addr); if (ret < 0) { pr_err("can't get fuse1 addr\n"); return -EINVAL; } ret = of_property_read_u32(node, "qcom,spss-fuse2-addr", &spss_fuse2_addr); if (ret < 0) { pr_err("can't get fuse2 addr\n"); return -EINVAL; } ret = of_property_read_u32(node, "qcom,spss-fuse1-bit", &spss_fuse1_bit); if (ret < 0) { pr_err("can't get fuse1 bit\n"); return -EINVAL; } ret = of_property_read_u32(node, "qcom,spss-fuse2-bit", &spss_fuse2_bit); if (ret < 0) { pr_err("can't get fuse2 bit\n"); return -EINVAL; } spss_fuse1_mask = BIT(spss_fuse1_bit); spss_fuse2_mask = BIT(spss_fuse2_bit); pr_debug("spss fuse1 addr [0x%x] bit [%d]\n", (int) spss_fuse1_addr, (int) spss_fuse1_bit); pr_debug("spss fuse2 addr [0x%x] bit [%d]\n", (int) spss_fuse2_addr, (int) spss_fuse2_bit); spss_fuse1_reg = ioremap_nocache(spss_fuse1_addr, sizeof(u32)); if (!spss_fuse1_reg) { pr_err("can't map fuse1 addr\n"); return -EINVAL; } spss_fuse2_reg = ioremap_nocache(spss_fuse2_addr, sizeof(u32)); if (!spss_fuse2_reg) { iounmap(spss_fuse1_reg); pr_err("can't map fuse2 addr\n"); return -EINVAL; } val1 = readl_relaxed(spss_fuse1_reg); val2 = readl_relaxed(spss_fuse2_reg); pr_debug("spss fuse1 value [0x%08x]\n", (int) val1); pr_debug("spss fuse2 value [0x%08x]\n", (int) val2); pr_debug("spss fuse1 mask [0x%08x]\n", (int) spss_fuse1_mask); pr_debug("spss fuse2 mask [0x%08x]\n", (int) spss_fuse2_mask); /** * Set firmware_type based on fuses: * SPSS_CONFIG_MODE 11: dev * SPSS_CONFIG_MODE 01 or 10: test * SPSS_CONFIG_MODE 00: prod */ if ((val1 & spss_fuse1_mask) && (val2 & spss_fuse2_mask)) firmware_type = SPSS_FW_TYPE_DEV; else if ((val1 & spss_fuse1_mask) || (val2 & spss_fuse2_mask)) firmware_type = SPSS_FW_TYPE_TEST; else firmware_type = SPSS_FW_TYPE_PROD; iounmap(spss_fuse1_reg); iounmap(spss_fuse2_reg); ret = of_property_read_u32(node, "qcom,spss-debug-reg-addr", &spss_debug_reg_addr); if (ret < 0) { pr_err("can't get debug regs addr\n"); return ret; } ret = of_property_read_u32(node, "qcom,spss-emul-type-reg-addr", &spss_emul_type_reg_addr); if (ret < 0) { pr_err("can't get spss-emulation-type-reg addr\n"); return -EINVAL; } spss_emul_type_reg = ioremap_nocache(spss_emul_type_reg_addr, sizeof(u32)); if (!spss_emul_type_reg) { pr_err("can't map soc-emulation-type reg addr\n"); return -EINVAL; } spss_emul_type_val = readl_relaxed(spss_emul_type_reg); pr_debug("spss_emul_type value [0x%08x]\n", (int)spss_emul_type_val); if ((spss_emul_type_val & SPU_EMULATUION) && !(spss_emul_type_val & SPU_PRESENT_IN_EMULATION)) { /* for some emulation platforms SPSS is not present */ firmware_type = SPSS_FW_TYPE_NONE; } iounmap(spss_emul_type_reg); return 0; } /** * spss_probe() - initialization sequence */ static int spss_probe(struct platform_device *pdev) { int ret = 0; struct device_node *np = NULL; struct device *dev = NULL; np = pdev->dev.of_node; dev = &pdev->dev; spss_dev = dev; platform_set_drvdata(pdev, dev); ret = spss_parse_dt(np); if (ret < 0) return ret; switch (firmware_type) { case SPSS_FW_TYPE_DEV: firmware_name = dev_firmware_name; break; case SPSS_FW_TYPE_TEST: firmware_name = test_firmware_name; break; case SPSS_FW_TYPE_PROD: firmware_name = prod_firmware_name; break; case SPSS_FW_TYPE_NONE: firmware_name = none_firmware_name; break; default: return -EINVAL; } ret = subsystem_set_fwname("spss", firmware_name); if (ret < 0) { pr_err("fail to set fw name\n"); return -EINVAL; } ret = spss_create_sysfs(dev); if (ret < 0) return ret; return 0; } static const struct of_device_id spss_match_table[] = { { .compatible = "qcom,spss-utils", }, { }, }; static struct platform_driver spss_driver = { .probe = spss_probe, .driver = { .name = DEVICE_NAME, .of_match_table = of_match_ptr(spss_match_table), }, }; /*==========================================================================*/ /* Driver Init/Exit */ /*==========================================================================*/ static int __init spss_init(void) { int ret = 0; ret = platform_driver_register(&spss_driver); if (ret) pr_err("register platform driver failed, ret [%d]\n", ret); return ret; } late_initcall(spss_init); /* start after PIL driver */ MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Secure Processor Utilities");