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>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/soundwire/sdw_intel.h>
18 #define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */
19 #define SDW_MAX_LINKS 4
20 #define SDW_SHIM_LCAP 0x0
21 #define SDW_SHIM_BASE 0x2C000
22 #define SDW_ALH_BASE 0x2C800
23 #define SDW_LINK_BASE 0x30000
24 #define SDW_LINK_SIZE 0x10000
27 module_param_named(sdw_link_mask
, link_mask
, int, 0444);
28 MODULE_PARM_DESC(sdw_link_mask
, "Intel link mask (one bit per link)");
30 static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx
*ctx
)
32 struct sdw_intel_link_res
*link
= ctx
->links
;
38 for (i
= 0; i
< ctx
->count
; i
++) {
40 platform_device_unregister(link
->pdev
);
50 static struct sdw_intel_ctx
51 *sdw_intel_add_controller(struct sdw_intel_res
*res
)
53 struct platform_device_info pdevinfo
;
54 struct platform_device
*pdev
;
55 struct sdw_intel_link_res
*link
;
56 struct sdw_intel_ctx
*ctx
;
57 struct acpi_device
*adev
;
62 if (acpi_bus_get_device(res
->handle
, &adev
))
65 /* Found controller, find links supported */
67 ret
= fwnode_property_read_u8_array(acpi_fwnode_handle(adev
),
68 "mipi-sdw-master-count", &count
, 1);
70 /* Don't fail on error, continue and use hw value */
73 "Failed to read mipi-sdw-master-count: %d\n", ret
);
74 count
= SDW_MAX_LINKS
;
77 /* Check SNDWLCAP.LCOUNT */
78 caps
= ioread32(res
->mmio_base
+ SDW_SHIM_BASE
+ SDW_SHIM_LCAP
);
79 caps
&= GENMASK(2, 0);
81 /* Check HW supported vs property value and use min of two */
82 count
= min_t(u8
, caps
, count
);
84 /* Check count is within bounds */
85 if (count
> SDW_MAX_LINKS
) {
86 dev_err(&adev
->dev
, "Link count %d exceeds max %d\n",
87 count
, SDW_MAX_LINKS
);
90 dev_warn(&adev
->dev
, "No SoundWire links detected\n");
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 if (link_mask
&& !(link_mask
& BIT(i
))) {
111 "Link %d masked, will not be enabled\n", i
);
116 link
->registers
= res
->mmio_base
+ SDW_LINK_BASE
117 + (SDW_LINK_SIZE
* i
);
118 link
->shim
= res
->mmio_base
+ SDW_SHIM_BASE
;
119 link
->alh
= res
->mmio_base
+ SDW_ALH_BASE
;
121 link
->ops
= res
->ops
;
122 link
->dev
= res
->dev
;
124 memset(&pdevinfo
, 0, sizeof(pdevinfo
));
126 pdevinfo
.parent
= res
->parent
;
127 pdevinfo
.name
= "int-sdw";
129 pdevinfo
.fwnode
= acpi_fwnode_handle(adev
);
131 pdev
= platform_device_register_full(&pdevinfo
);
134 "platform device creation failed: %ld\n",
146 sdw_intel_cleanup_pdev(ctx
);
152 static acpi_status
sdw_intel_acpi_cb(acpi_handle handle
, u32 level
,
153 void *cdata
, void **return_value
)
155 struct sdw_intel_res
*res
= cdata
;
156 struct acpi_device
*adev
;
160 status
= acpi_evaluate_integer(handle
, METHOD_NAME__ADR
, NULL
, &adr
);
161 if (ACPI_FAILURE(status
))
162 return AE_OK
; /* keep going */
164 if (acpi_bus_get_device(handle
, &adev
)) {
165 pr_err("%s: Couldn't find ACPI handle\n", __func__
);
169 res
->handle
= handle
;
172 * On some Intel platforms, multiple children of the HDAS
173 * device can be found, but only one of them is the SoundWire
174 * controller. The SNDW device is always exposed with
175 * Name(_ADR, 0x40000000), with bits 31..28 representing the
176 * SoundWire link so filter accordingly
178 if ((adr
& GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE
)
179 return AE_OK
; /* keep going */
181 /* device found, stop namespace walk */
182 return AE_CTRL_TERMINATE
;
186 * sdw_intel_init() - SoundWire Intel init routine
187 * @parent_handle: ACPI parent handle
188 * @res: resource data
190 * This scans the namespace and creates SoundWire link controller devices
191 * based on the info queried.
193 void *sdw_intel_init(acpi_handle
*parent_handle
, struct sdw_intel_res
*res
)
197 status
= acpi_walk_namespace(ACPI_TYPE_DEVICE
,
201 if (ACPI_FAILURE(status
))
204 return sdw_intel_add_controller(res
);
208 * sdw_intel_exit() - SoundWire Intel exit
209 * @arg: callback context
211 * Delete the controller instances created and cleanup
213 void sdw_intel_exit(struct sdw_intel_ctx
*ctx
)
215 sdw_intel_cleanup_pdev(ctx
);
218 EXPORT_SYMBOL(sdw_intel_exit
);
220 MODULE_LICENSE("Dual BSD/GPL");
221 MODULE_DESCRIPTION("Intel Soundwire Init Library");