1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2 // Copyright(c) 2015-17 Intel Corporation.
5 * SDW Intel Init Routines
7 * Initializes and creates SDW devices based on ACPI and Hardware values
10 #include <linux/acpi.h>
11 #include <linux/export.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/soundwire/sdw_intel.h>
17 #define SDW_MAX_LINKS 4
18 #define SDW_SHIM_LCAP 0x0
19 #define SDW_SHIM_BASE 0x2C000
20 #define SDW_ALH_BASE 0x2C800
21 #define SDW_LINK_BASE 0x30000
22 #define SDW_LINK_SIZE 0x10000
24 struct sdw_link_data
{
25 struct sdw_intel_link_res res
;
26 struct platform_device
*pdev
;
29 struct sdw_intel_ctx
{
31 struct sdw_link_data
*links
;
34 static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx
*ctx
)
36 struct sdw_link_data
*link
= ctx
->links
;
42 for (i
= 0; i
< ctx
->count
; i
++) {
44 platform_device_unregister(link
->pdev
);
54 static struct sdw_intel_ctx
55 *sdw_intel_add_controller(struct sdw_intel_res
*res
)
57 struct platform_device_info pdevinfo
;
58 struct platform_device
*pdev
;
59 struct sdw_link_data
*link
;
60 struct sdw_intel_ctx
*ctx
;
61 struct acpi_device
*adev
;
66 if (acpi_bus_get_device(res
->handle
, &adev
))
69 /* Found controller, find links supported */
71 ret
= fwnode_property_read_u8_array(acpi_fwnode_handle(adev
),
72 "mipi-sdw-master-count", &count
, 1);
74 /* Don't fail on error, continue and use hw value */
77 "Failed to read mipi-sdw-master-count: %d\n", ret
);
78 count
= SDW_MAX_LINKS
;
81 /* Check SNDWLCAP.LCOUNT */
82 caps
= ioread32(res
->mmio_base
+ SDW_SHIM_BASE
+ SDW_SHIM_LCAP
);
84 /* Check HW supported vs property value and use min of two */
85 count
= min_t(u8
, caps
, count
);
87 /* Check count is within bounds */
88 if (count
> SDW_MAX_LINKS
) {
89 dev_err(&adev
->dev
, "Link count %d exceeds max %d\n",
90 count
, SDW_MAX_LINKS
);
94 dev_dbg(&adev
->dev
, "Creating %d SDW Link devices\n", count
);
96 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
101 ctx
->links
= kcalloc(ctx
->count
, sizeof(*ctx
->links
), GFP_KERNEL
);
107 /* Create SDW Master devices */
108 for (i
= 0; i
< count
; i
++) {
109 link
->res
.irq
= res
->irq
;
110 link
->res
.registers
= res
->mmio_base
+ SDW_LINK_BASE
111 + (SDW_LINK_SIZE
* i
);
112 link
->res
.shim
= res
->mmio_base
+ SDW_SHIM_BASE
;
113 link
->res
.alh
= res
->mmio_base
+ SDW_ALH_BASE
;
115 link
->res
.ops
= res
->ops
;
116 link
->res
.arg
= res
->arg
;
118 memset(&pdevinfo
, 0, sizeof(pdevinfo
));
120 pdevinfo
.parent
= res
->parent
;
121 pdevinfo
.name
= "int-sdw";
123 pdevinfo
.fwnode
= acpi_fwnode_handle(adev
);
124 pdevinfo
.data
= &link
->res
;
125 pdevinfo
.size_data
= sizeof(link
->res
);
127 pdev
= platform_device_register_full(&pdevinfo
);
130 "platform device creation failed: %ld\n",
142 sdw_intel_cleanup_pdev(ctx
);
148 static acpi_status
sdw_intel_acpi_cb(acpi_handle handle
, u32 level
,
149 void *cdata
, void **return_value
)
151 struct sdw_intel_res
*res
= cdata
;
152 struct acpi_device
*adev
;
154 if (acpi_bus_get_device(handle
, &adev
)) {
155 pr_err("%s: Couldn't find ACPI handle\n", __func__
);
159 res
->handle
= handle
;
164 * sdw_intel_init() - SoundWire Intel init routine
165 * @parent_handle: ACPI parent handle
166 * @res: resource data
168 * This scans the namespace and creates SoundWire link controller devices
169 * based on the info queried.
171 void *sdw_intel_init(acpi_handle
*parent_handle
, struct sdw_intel_res
*res
)
175 status
= acpi_walk_namespace(ACPI_TYPE_DEVICE
,
179 if (ACPI_FAILURE(status
))
182 return sdw_intel_add_controller(res
);
184 EXPORT_SYMBOL(sdw_intel_init
);
187 * sdw_intel_exit() - SoundWire Intel exit
188 * @arg: callback context
190 * Delete the controller instances created and cleanup
192 void sdw_intel_exit(void *arg
)
194 struct sdw_intel_ctx
*ctx
= arg
;
196 sdw_intel_cleanup_pdev(ctx
);
199 EXPORT_SYMBOL(sdw_intel_exit
);
201 MODULE_LICENSE("Dual BSD/GPL");
202 MODULE_DESCRIPTION("Intel Soundwire Init Library");