Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soundwire: intel: Add Intel init module

The SoundWire Master is implemented as part of Audio controller in
Intel platforms. Add a init module which creates SoundWire Master
platform devices based on the links supported in the hardware.

Signed-off-by: Sanyog Kale <sanyog.r.kale@intel.com>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Acked-By: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Vinod Koul and committed by
Greg Kroah-Hartman
d62a7d41 71bb8a1b

+204
+3
drivers/soundwire/Makefile
··· 13 13 #Intel driver 14 14 soundwire-intel-objs := intel.o 15 15 obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o 16 + 17 + soundwire-intel-init-objs := intel_init.o 18 + obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel-init.o
+198
drivers/soundwire/intel_init.c
··· 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");
+3
include/linux/soundwire/sdw_intel.h
··· 18 18 struct device *parent; 19 19 }; 20 20 21 + void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res); 22 + void sdw_intel_exit(void *arg); 23 + 21 24 #endif