1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright 2011 Broadcom Corporation. All rights reserved. */ 3 4 #include <linux/platform_device.h> 5 6 #include <linux/init.h> 7 #include <linux/slab.h> 8 #include <linux/module.h> 9 10 #include "bcm2835.h" 11 12 static bool enable_hdmi; 13 static bool enable_headphones; 14 static bool enable_compat_alsa = true; 15 static int num_channels = MAX_SUBSTREAMS; 16 17 module_param(enable_hdmi, bool, 0444); 18 MODULE_PARM_DESC(enable_hdmi, "Enables HDMI virtual audio device"); 19 module_param(enable_headphones, bool, 0444); 20 MODULE_PARM_DESC(enable_headphones, "Enables Headphones virtual audio device"); 21 module_param(enable_compat_alsa, bool, 0444); 22 MODULE_PARM_DESC(enable_compat_alsa, 23 "Enables ALSA compatibility virtual audio device"); 24 module_param(num_channels, int, 0644); 25 MODULE_PARM_DESC(num_channels, "Number of audio channels (default: 8)"); 26 27 static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res) 28 { 29 struct bcm2835_vchi_ctx *vchi_ctx = res; 30 31 bcm2835_free_vchi_ctx(vchi_ctx); 32 } 33 34 static int bcm2835_devm_add_vchi_ctx(struct device *dev) 35 { 36 struct bcm2835_vchi_ctx *vchi_ctx; 37 int ret; 38 39 vchi_ctx = devres_alloc(bcm2835_devm_free_vchi_ctx, sizeof(*vchi_ctx), 40 GFP_KERNEL); 41 if (!vchi_ctx) 42 return -ENOMEM; 43 44 ret = bcm2835_new_vchi_ctx(dev, vchi_ctx); 45 if (ret) { 46 devres_free(vchi_ctx); 47 return ret; 48 } 49 50 devres_add(dev, vchi_ctx); 51 52 return 0; 53 } 54 55 typedef int (*bcm2835_audio_newpcm_func)(struct bcm2835_chip *chip, 56 const char *name, 57 enum snd_bcm2835_route route, 58 u32 numchannels); 59 60 typedef int (*bcm2835_audio_newctl_func)(struct bcm2835_chip *chip); 61 62 struct bcm2835_audio_driver { 63 struct device_driver driver; 64 const char *shortname; 65 const char *longname; 66 int minchannels; 67 bcm2835_audio_newpcm_func newpcm; 68 bcm2835_audio_newctl_func newctl; 69 enum snd_bcm2835_route route; 70 }; 71 72 static int bcm2835_audio_alsa_newpcm(struct bcm2835_chip *chip, 73 const char *name, 74 enum snd_bcm2835_route route, 75 u32 numchannels) 76 { 77 int err; 78 79 err = snd_bcm2835_new_pcm(chip, "bcm2835 ALSA", 0, AUDIO_DEST_AUTO, 80 numchannels - 1, false); 81 if (err) 82 return err; 83 84 err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true); 85 if (err) 86 return err; 87 88 return 0; 89 } 90 91 static int bcm2835_audio_simple_newpcm(struct bcm2835_chip *chip, 92 const char *name, 93 enum snd_bcm2835_route route, 94 u32 numchannels) 95 { 96 return snd_bcm2835_new_pcm(chip, name, 0, route, numchannels, false); 97 } 98 99 static struct bcm2835_audio_driver bcm2835_audio_alsa = { 100 .driver = { 101 .name = "bcm2835_alsa", 102 .owner = THIS_MODULE, 103 }, 104 .shortname = "bcm2835 ALSA", 105 .longname = "bcm2835 ALSA", 106 .minchannels = 2, 107 .newpcm = bcm2835_audio_alsa_newpcm, 108 .newctl = snd_bcm2835_new_ctl, 109 }; 110 111 static struct bcm2835_audio_driver bcm2835_audio_hdmi = { 112 .driver = { 113 .name = "bcm2835_hdmi", 114 .owner = THIS_MODULE, 115 }, 116 .shortname = "bcm2835 HDMI", 117 .longname = "bcm2835 HDMI", 118 .minchannels = 1, 119 .newpcm = bcm2835_audio_simple_newpcm, 120 .newctl = snd_bcm2835_new_hdmi_ctl, 121 .route = AUDIO_DEST_HDMI 122 }; 123 124 static struct bcm2835_audio_driver bcm2835_audio_headphones = { 125 .driver = { 126 .name = "bcm2835_headphones", 127 .owner = THIS_MODULE, 128 }, 129 .shortname = "bcm2835 Headphones", 130 .longname = "bcm2835 Headphones", 131 .minchannels = 1, 132 .newpcm = bcm2835_audio_simple_newpcm, 133 .newctl = snd_bcm2835_new_headphones_ctl, 134 .route = AUDIO_DEST_HEADPHONES 135 }; 136 137 struct bcm2835_audio_drivers { 138 struct bcm2835_audio_driver *audio_driver; 139 const bool *is_enabled; 140 }; 141 142 static struct bcm2835_audio_drivers children_devices[] = { 143 { 144 .audio_driver = &bcm2835_audio_alsa, 145 .is_enabled = &enable_compat_alsa, 146 }, 147 { 148 .audio_driver = &bcm2835_audio_hdmi, 149 .is_enabled = &enable_hdmi, 150 }, 151 { 152 .audio_driver = &bcm2835_audio_headphones, 153 .is_enabled = &enable_headphones, 154 }, 155 }; 156 157 static void bcm2835_card_free(void *data) 158 { 159 snd_card_free(data); 160 } 161 162 static int snd_add_child_device(struct device *dev, 163 struct bcm2835_audio_driver *audio_driver, 164 u32 numchans) 165 { 166 struct bcm2835_chip *chip; 167 struct snd_card *card; 168 int err; 169 170 err = snd_card_new(dev, -1, NULL, THIS_MODULE, sizeof(*chip), &card); 171 if (err < 0) { 172 dev_err(dev, "Failed to create card"); 173 return err; 174 } 175 176 chip = card->private_data; 177 chip->card = card; 178 chip->dev = dev; 179 mutex_init(&chip->audio_mutex); 180 181 chip->vchi_ctx = devres_find(dev, 182 bcm2835_devm_free_vchi_ctx, NULL, NULL); 183 if (!chip->vchi_ctx) { 184 err = -ENODEV; 185 goto error; 186 } 187 188 strscpy(card->driver, audio_driver->driver.name, sizeof(card->driver)); 189 strscpy(card->shortname, audio_driver->shortname, sizeof(card->shortname)); 190 strscpy(card->longname, audio_driver->longname, sizeof(card->longname)); 191 192 err = audio_driver->newpcm(chip, audio_driver->shortname, 193 audio_driver->route, 194 numchans); 195 if (err) { 196 dev_err(dev, "Failed to create pcm, error %d\n", err); 197 goto error; 198 } 199 200 err = audio_driver->newctl(chip); 201 if (err) { 202 dev_err(dev, "Failed to create controls, error %d\n", err); 203 goto error; 204 } 205 206 err = snd_card_register(card); 207 if (err) { 208 dev_err(dev, "Failed to register card, error %d\n", err); 209 goto error; 210 } 211 212 dev_set_drvdata(dev, chip); 213 214 err = devm_add_action(dev, bcm2835_card_free, card); 215 if (err < 0) { 216 dev_err(dev, "Failed to add devm action, err %d\n", err); 217 goto error; 218 } 219 220 dev_info(dev, "card created with %d channels\n", numchans); 221 return 0; 222 223 error: 224 snd_card_free(card); 225 return err; 226 } 227 228 static int snd_add_child_devices(struct device *device, u32 numchans) 229 { 230 int extrachannels_per_driver = 0; 231 int extrachannels_remainder = 0; 232 int count_devices = 0; 233 int extrachannels = 0; 234 int minchannels = 0; 235 int i; 236 237 for (i = 0; i < ARRAY_SIZE(children_devices); i++) 238 if (*children_devices[i].is_enabled) 239 count_devices++; 240 241 if (!count_devices) 242 return 0; 243 244 for (i = 0; i < ARRAY_SIZE(children_devices); i++) 245 if (*children_devices[i].is_enabled) 246 minchannels += 247 children_devices[i].audio_driver->minchannels; 248 249 if (minchannels < numchans) { 250 extrachannels = numchans - minchannels; 251 extrachannels_per_driver = extrachannels / count_devices; 252 extrachannels_remainder = extrachannels % count_devices; 253 } 254 255 dev_dbg(device, "minchannels %d\n", minchannels); 256 dev_dbg(device, "extrachannels %d\n", extrachannels); 257 dev_dbg(device, "extrachannels_per_driver %d\n", 258 extrachannels_per_driver); 259 dev_dbg(device, "extrachannels_remainder %d\n", 260 extrachannels_remainder); 261 262 for (i = 0; i < ARRAY_SIZE(children_devices); i++) { 263 struct bcm2835_audio_driver *audio_driver; 264 int numchannels_this_device; 265 int err; 266 267 if (!*children_devices[i].is_enabled) 268 continue; 269 270 audio_driver = children_devices[i].audio_driver; 271 272 if (audio_driver->minchannels > numchans) { 273 dev_err(device, 274 "Out of channels, needed %d but only %d left\n", 275 audio_driver->minchannels, 276 numchans); 277 continue; 278 } 279 280 numchannels_this_device = 281 audio_driver->minchannels + extrachannels_per_driver + 282 extrachannels_remainder; 283 extrachannels_remainder = 0; 284 285 numchans -= numchannels_this_device; 286 287 err = snd_add_child_device(device, audio_driver, 288 numchannels_this_device); 289 if (err) 290 return err; 291 } 292 293 return 0; 294 } 295 296 static int snd_bcm2835_alsa_probe(struct platform_device *pdev) 297 { 298 struct device *dev = &pdev->dev; 299 int err; 300 301 if (num_channels <= 0 || num_channels > MAX_SUBSTREAMS) { 302 num_channels = MAX_SUBSTREAMS; 303 dev_warn(dev, "Illegal num_channels value, will use %u\n", 304 num_channels); 305 } 306 307 err = bcm2835_devm_add_vchi_ctx(dev); 308 if (err) 309 return err; 310 311 err = snd_add_child_devices(dev, num_channels); 312 if (err) 313 return err; 314 315 return 0; 316 } 317 318 #ifdef CONFIG_PM 319 320 static int snd_bcm2835_alsa_suspend(struct platform_device *pdev, 321 pm_message_t state) 322 { 323 return 0; 324 } 325 326 static int snd_bcm2835_alsa_resume(struct platform_device *pdev) 327 { 328 return 0; 329 } 330 331 #endif 332 333 static struct platform_driver bcm2835_alsa_driver = { 334 .probe = snd_bcm2835_alsa_probe, 335 #ifdef CONFIG_PM 336 .suspend = snd_bcm2835_alsa_suspend, 337 .resume = snd_bcm2835_alsa_resume, 338 #endif 339 .driver = { 340 .name = "bcm2835_audio", 341 }, 342 }; 343 module_platform_driver(bcm2835_alsa_driver); 344 345 MODULE_AUTHOR("Dom Cobley"); 346 MODULE_DESCRIPTION("Alsa driver for BCM2835 chip"); 347 MODULE_LICENSE("GPL"); 348 MODULE_ALIAS("platform:bcm2835_audio"); 349