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 memset(&pdevinfo, 0, sizeof(pdevinfo)); 115 116 pdevinfo.parent = res->parent; 117 pdevinfo.name = "int-sdw"; 118 pdevinfo.id = i; 119 pdevinfo.fwnode = acpi_fwnode_handle(adev); 120 pdevinfo.data = &link->res; 121 pdevinfo.size_data = sizeof(link->res); 122 123 pdev = platform_device_register_full(&pdevinfo); 124 if (IS_ERR(pdev)) { 125 dev_err(&adev->dev, 126 "platform device creation failed: %ld\n", 127 PTR_ERR(pdev)); 128 goto pdev_err; 129 } 130 131 link->pdev = pdev; 132 link++; 133 } 134 135 return ctx; 136 137 pdev_err: 138 sdw_intel_cleanup_pdev(ctx); 139 link_err: 140 kfree(ctx); 141 return NULL; 142 } 143 144 static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, 145 void *cdata, void **return_value) 146 { 147 struct sdw_intel_res *res = cdata; 148 struct acpi_device *adev; 149 150 if (acpi_bus_get_device(handle, &adev)) { 151 dev_err(&adev->dev, "Couldn't find ACPI handle\n"); 152 return AE_NOT_FOUND; 153 } 154 155 res->handle = handle; 156 return AE_OK; 157 } 158 159 /** 160 * sdw_intel_init() - SoundWire Intel init routine 161 * @parent_handle: ACPI parent handle 162 * @res: resource data 163 * 164 * This scans the namespace and creates SoundWire link controller devices 165 * based on the info queried. 166 */ 167 void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res) 168 { 169 acpi_status status; 170 171 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, 172 parent_handle, 1, 173 sdw_intel_acpi_cb, 174 NULL, res, NULL); 175 if (ACPI_FAILURE(status)) 176 return NULL; 177 178 return sdw_intel_add_controller(res); 179 } 180 EXPORT_SYMBOL(sdw_intel_init); 181 182 /** 183 * sdw_intel_exit() - SoundWire Intel exit 184 * @arg: callback context 185 * 186 * Delete the controller instances created and cleanup 187 */ 188 void sdw_intel_exit(void *arg) 189 { 190 struct sdw_intel_ctx *ctx = arg; 191 192 sdw_intel_cleanup_pdev(ctx); 193 kfree(ctx); 194 } 195 EXPORT_SYMBOL(sdw_intel_exit); 196 197 MODULE_LICENSE("Dual BSD/GPL"); 198 MODULE_DESCRIPTION("Intel Soundwire Init Library"); 199