1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 // Copyright(c) 2015-17 Intel Corporation. 3 4 /* 5 * SDW Intel Init Routines 6 * 7 * Initializes and creates SDW devices based on ACPI and Hardware values 8 */ 9 10 #include <linux/acpi.h> 11 #include <linux/platform_device.h> 12 #include <linux/soundwire/sdw_intel.h> 13 #include "intel.h" 14 15 #define SDW_MAX_LINKS 4 16 #define SDW_SHIM_LCAP 0x0 17 #define SDW_SHIM_BASE 0x2C000 18 #define SDW_ALH_BASE 0x2C800 19 #define SDW_LINK_BASE 0x30000 20 #define SDW_LINK_SIZE 0x10000 21 22 struct sdw_link_data { 23 struct sdw_intel_link_res res; 24 struct platform_device *pdev; 25 }; 26 27 struct sdw_intel_ctx { 28 int count; 29 struct sdw_link_data *links; 30 }; 31 32 static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx *ctx) 33 { 34 struct sdw_link_data *link = ctx->links; 35 int i; 36 37 if (!link) 38 return 0; 39 40 for (i = 0; i < ctx->count; i++) { 41 if (link->pdev) 42 platform_device_unregister(link->pdev); 43 link++; 44 } 45 46 kfree(ctx->links); 47 ctx->links = NULL; 48 49 return 0; 50 } 51 52 static struct sdw_intel_ctx 53 *sdw_intel_add_controller(struct sdw_intel_res *res) 54 { 55 struct platform_device_info pdevinfo; 56 struct platform_device *pdev; 57 struct sdw_link_data *link; 58 struct sdw_intel_ctx *ctx; 59 struct acpi_device *adev; 60 int ret, i; 61 u8 count; 62 u32 caps; 63 64 if (acpi_bus_get_device(res->handle, &adev)) 65 return NULL; 66 67 /* Found controller, find links supported */ 68 count = 0; 69 ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev), 70 "mipi-sdw-master-count", &count, 1); 71 72 /* Don't fail on error, continue and use hw value */ 73 if (ret) { 74 dev_err(&adev->dev, 75 "Failed to read mipi-sdw-master-count: %d\n", ret); 76 count = SDW_MAX_LINKS; 77 } 78 79 /* Check SNDWLCAP.LCOUNT */ 80 caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP); 81 82 /* Check HW supported vs property value and use min of two */ 83 count = min_t(u8, caps, count); 84 85 /* Check count is within bounds */ 86 if (count > SDW_MAX_LINKS) { 87 dev_err(&adev->dev, "Link count %d exceeds max %d\n", 88 count, SDW_MAX_LINKS); 89 return NULL; 90 } 91 92 dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count); 93 94 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 95 if (!ctx) 96 return NULL; 97 98 ctx->count = count; 99 ctx->links = kcalloc(ctx->count, sizeof(*ctx->links), GFP_KERNEL); 100 if (!ctx->links) 101 goto link_err; 102 103 link = ctx->links; 104 105 /* Create SDW Master devices */ 106 for (i = 0; i < count; i++) { 107 108 link->res.irq = res->irq; 109 link->res.registers = res->mmio_base + SDW_LINK_BASE 110 + (SDW_LINK_SIZE * i); 111 link->res.shim = res->mmio_base + SDW_SHIM_BASE; 112 link->res.alh = res->mmio_base + SDW_ALH_BASE; 113 114 link->res.ops = res->ops; 115 link->res.arg = res->arg; 116 117 memset(&pdevinfo, 0, sizeof(pdevinfo)); 118 119 pdevinfo.parent = res->parent; 120 pdevinfo.name = "int-sdw"; 121 pdevinfo.id = i; 122 pdevinfo.fwnode = acpi_fwnode_handle(adev); 123 pdevinfo.data = &link->res; 124 pdevinfo.size_data = sizeof(link->res); 125 126 pdev = platform_device_register_full(&pdevinfo); 127 if (IS_ERR(pdev)) { 128 dev_err(&adev->dev, 129 "platform device creation failed: %ld\n", 130 PTR_ERR(pdev)); 131 goto pdev_err; 132 } 133 134 link->pdev = pdev; 135 link++; 136 } 137 138 return ctx; 139 140 pdev_err: 141 sdw_intel_cleanup_pdev(ctx); 142 link_err: 143 kfree(ctx); 144 return NULL; 145 } 146 147 static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, 148 void *cdata, void **return_value) 149 { 150 struct sdw_intel_res *res = cdata; 151 struct acpi_device *adev; 152 153 if (acpi_bus_get_device(handle, &adev)) { 154 pr_err("%s: Couldn't find ACPI handle\n", __func__); 155 return AE_NOT_FOUND; 156 } 157 158 res->handle = handle; 159 return AE_OK; 160 } 161 162 /** 163 * sdw_intel_init() - SoundWire Intel init routine 164 * @parent_handle: ACPI parent handle 165 * @res: resource data 166 * 167 * This scans the namespace and creates SoundWire link controller devices 168 * based on the info queried. 169 */ 170 void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res) 171 { 172 acpi_status status; 173 174 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, 175 parent_handle, 1, 176 sdw_intel_acpi_cb, 177 NULL, res, NULL); 178 if (ACPI_FAILURE(status)) 179 return NULL; 180 181 return sdw_intel_add_controller(res); 182 } 183 EXPORT_SYMBOL(sdw_intel_init); 184 185 /** 186 * sdw_intel_exit() - SoundWire Intel exit 187 * @arg: callback context 188 * 189 * Delete the controller instances created and cleanup 190 */ 191 void sdw_intel_exit(void *arg) 192 { 193 struct sdw_intel_ctx *ctx = arg; 194 195 sdw_intel_cleanup_pdev(ctx); 196 kfree(ctx); 197 } 198 EXPORT_SYMBOL(sdw_intel_exit); 199 200 MODULE_LICENSE("Dual BSD/GPL"); 201 MODULE_DESCRIPTION("Intel Soundwire Init Library"); 202