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/platform_device.h>
12 #include <linux/soundwire/sdw_intel.h>
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
22 struct sdw_link_data
{
23 struct sdw_intel_link_res res
;
24 struct platform_device
*pdev
;
27 struct sdw_intel_ctx
{
29 struct sdw_link_data
*links
;
32 static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx
*ctx
)
34 struct sdw_link_data
*link
= ctx
->links
;
40 for (i
= 0; i
< ctx
->count
; i
++) {
42 platform_device_unregister(link
->pdev
);
52 static struct sdw_intel_ctx
53 *sdw_intel_add_controller(struct sdw_intel_res
*res
)
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
;
64 if (acpi_bus_get_device(res
->handle
, &adev
))
67 /* Found controller, find links supported */
69 ret
= fwnode_property_read_u8_array(acpi_fwnode_handle(adev
),
70 "mipi-sdw-master-count", &count
, 1);
72 /* Don't fail on error, continue and use hw value */
75 "Failed to read mipi-sdw-master-count: %d\n", ret
);
76 count
= SDW_MAX_LINKS
;
79 /* Check SNDWLCAP.LCOUNT */
80 caps
= ioread32(res
->mmio_base
+ SDW_SHIM_BASE
+ SDW_SHIM_LCAP
);
82 /* Check HW supported vs property value and use min of two */
83 count
= min_t(u8
, caps
, count
);
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
);
92 dev_dbg(&adev
->dev
, "Creating %d SDW Link devices\n", count
);
94 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
99 ctx
->links
= kcalloc(ctx
->count
, sizeof(*ctx
->links
), GFP_KERNEL
);
105 /* Create SDW Master devices */
106 for (i
= 0; i
< count
; i
++) {
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
;
114 link
->res
.ops
= res
->ops
;
115 link
->res
.arg
= res
->arg
;
117 memset(&pdevinfo
, 0, sizeof(pdevinfo
));
119 pdevinfo
.parent
= res
->parent
;
120 pdevinfo
.name
= "int-sdw";
122 pdevinfo
.fwnode
= acpi_fwnode_handle(adev
);
123 pdevinfo
.data
= &link
->res
;
124 pdevinfo
.size_data
= sizeof(link
->res
);
126 pdev
= platform_device_register_full(&pdevinfo
);
129 "platform device creation failed: %ld\n",
141 sdw_intel_cleanup_pdev(ctx
);
147 static acpi_status
sdw_intel_acpi_cb(acpi_handle handle
, u32 level
,
148 void *cdata
, void **return_value
)
150 struct sdw_intel_res
*res
= cdata
;
151 struct acpi_device
*adev
;
153 if (acpi_bus_get_device(handle
, &adev
)) {
154 dev_err(&adev
->dev
, "Couldn't find ACPI handle\n");
158 res
->handle
= handle
;
163 * sdw_intel_init() - SoundWire Intel init routine
164 * @parent_handle: ACPI parent handle
165 * @res: resource data
167 * This scans the namespace and creates SoundWire link controller devices
168 * based on the info queried.
170 void *sdw_intel_init(acpi_handle
*parent_handle
, struct sdw_intel_res
*res
)
174 status
= acpi_walk_namespace(ACPI_TYPE_DEVICE
,
178 if (ACPI_FAILURE(status
))
181 return sdw_intel_add_controller(res
);
183 EXPORT_SYMBOL(sdw_intel_init
);
186 * sdw_intel_exit() - SoundWire Intel exit
187 * @arg: callback context
189 * Delete the controller instances created and cleanup
191 void sdw_intel_exit(void *arg
)
193 struct sdw_intel_ctx
*ctx
= arg
;
195 sdw_intel_cleanup_pdev(ctx
);
198 EXPORT_SYMBOL(sdw_intel_exit
);
200 MODULE_LICENSE("Dual BSD/GPL");
201 MODULE_DESCRIPTION("Intel Soundwire Init Library");