]> Git Repo - linux.git/blob - drivers/soundwire/intel_init.c
ring-buffer: Redefine the unimplemented RINGBUF_TYPE_TIME_STAMP
[linux.git] / 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");
This page took 0.06384 seconds and 4 git commands to generate.