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