557 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>4 */5 6#include <linux/module.h>7#include <linux/bitops.h>8#include <linux/clk.h>9#include <linux/device.h>10#include <linux/idr.h>11#include <linux/list.h>12#include <linux/mutex.h>13#include <linux/of.h>14#include <linux/pm.h>15#include <linux/pm_runtime.h>16#include <linux/slab.h>17#include <linux/sysfs.h>18#include <sound/ac97_codec.h>19#include <sound/ac97/codec.h>20#include <sound/ac97/controller.h>21#include <sound/ac97/regs.h>22 23#include "ac97_core.h"24 25/*26 * Protects ac97_controllers and each ac97_controller structure.27 */28static DEFINE_MUTEX(ac97_controllers_mutex);29static DEFINE_IDR(ac97_adapter_idr);30static LIST_HEAD(ac97_controllers);31 32static inline struct ac97_controller*33to_ac97_controller(struct device *ac97_adapter)34{35 return container_of(ac97_adapter, struct ac97_controller, adap);36}37 38static int ac97_unbound_ctrl_write(struct ac97_controller *adrv, int slot,39 unsigned short reg, unsigned short val)40{41 return -ENODEV;42}43 44static int ac97_unbound_ctrl_read(struct ac97_controller *adrv, int slot,45 unsigned short reg)46{47 return -ENODEV;48}49 50static const struct ac97_controller_ops ac97_unbound_ctrl_ops = {51 .write = ac97_unbound_ctrl_write,52 .read = ac97_unbound_ctrl_read,53};54 55static struct ac97_controller ac97_unbound_ctrl = {56 .ops = &ac97_unbound_ctrl_ops,57};58 59static struct ac97_codec_device *60ac97_codec_find(struct ac97_controller *ac97_ctrl, unsigned int codec_num)61{62 if (codec_num >= AC97_BUS_MAX_CODECS)63 return ERR_PTR(-EINVAL);64 65 return ac97_ctrl->codecs[codec_num];66}67 68static struct device_node *69ac97_of_get_child_device(struct ac97_controller *ac97_ctrl, int idx,70 unsigned int vendor_id)71{72 struct device_node *node;73 u32 reg;74 char compat[] = "ac97,0000,0000";75 76 snprintf(compat, sizeof(compat), "ac97,%04x,%04x",77 vendor_id >> 16, vendor_id & 0xffff);78 79 for_each_child_of_node(ac97_ctrl->parent->of_node, node) {80 if ((idx != of_property_read_u32(node, "reg", ®)) ||81 !of_device_is_compatible(node, compat))82 continue;83 return node;84 }85 86 return NULL;87}88 89static void ac97_codec_release(struct device *dev)90{91 struct ac97_codec_device *adev;92 struct ac97_controller *ac97_ctrl;93 94 adev = to_ac97_device(dev);95 ac97_ctrl = adev->ac97_ctrl;96 ac97_ctrl->codecs[adev->num] = NULL;97 of_node_put(dev->of_node);98 kfree(adev);99}100 101static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,102 unsigned int vendor_id)103{104 struct ac97_codec_device *codec;105 int ret;106 107 codec = kzalloc(sizeof(*codec), GFP_KERNEL);108 if (!codec)109 return -ENOMEM;110 ac97_ctrl->codecs[idx] = codec;111 codec->vendor_id = vendor_id;112 codec->dev.release = ac97_codec_release;113 codec->dev.bus = &ac97_bus_type;114 codec->dev.parent = &ac97_ctrl->adap;115 codec->num = idx;116 codec->ac97_ctrl = ac97_ctrl;117 118 device_initialize(&codec->dev);119 dev_set_name(&codec->dev, "%s:%u", dev_name(ac97_ctrl->parent), idx);120 codec->dev.of_node = ac97_of_get_child_device(ac97_ctrl, idx,121 vendor_id);122 123 ret = device_add(&codec->dev);124 if (ret) {125 put_device(&codec->dev);126 return ret;127 }128 129 return 0;130}131 132unsigned int snd_ac97_bus_scan_one(struct ac97_controller *adrv,133 unsigned int codec_num)134{135 unsigned short vid1, vid2;136 int ret;137 138 ret = adrv->ops->read(adrv, codec_num, AC97_VENDOR_ID1);139 vid1 = (ret & 0xffff);140 if (ret < 0)141 return 0;142 143 ret = adrv->ops->read(adrv, codec_num, AC97_VENDOR_ID2);144 vid2 = (ret & 0xffff);145 if (ret < 0)146 return 0;147 148 dev_dbg(&adrv->adap, "%s(codec_num=%u): vendor_id=0x%08x\n",149 __func__, codec_num, AC97_ID(vid1, vid2));150 return AC97_ID(vid1, vid2);151}152 153static int ac97_bus_scan(struct ac97_controller *ac97_ctrl)154{155 int ret, i;156 unsigned int vendor_id;157 158 for (i = 0; i < AC97_BUS_MAX_CODECS; i++) {159 if (ac97_codec_find(ac97_ctrl, i))160 continue;161 if (!(ac97_ctrl->slots_available & BIT(i)))162 continue;163 vendor_id = snd_ac97_bus_scan_one(ac97_ctrl, i);164 if (!vendor_id)165 continue;166 167 ret = ac97_codec_add(ac97_ctrl, i, vendor_id);168 if (ret < 0)169 return ret;170 }171 return 0;172}173 174static int ac97_bus_reset(struct ac97_controller *ac97_ctrl)175{176 ac97_ctrl->ops->reset(ac97_ctrl);177 178 return 0;179}180 181/**182 * snd_ac97_codec_driver_register - register an AC97 codec driver183 * @dev: AC97 driver codec to register184 *185 * Register an AC97 codec driver to the ac97 bus driver, aka. the AC97 digital186 * controller.187 *188 * Returns 0 on success or error code189 */190int snd_ac97_codec_driver_register(struct ac97_codec_driver *drv)191{192 drv->driver.bus = &ac97_bus_type;193 return driver_register(&drv->driver);194}195EXPORT_SYMBOL_GPL(snd_ac97_codec_driver_register);196 197/**198 * snd_ac97_codec_driver_unregister - unregister an AC97 codec driver199 * @dev: AC97 codec driver to unregister200 *201 * Unregister a previously registered ac97 codec driver.202 */203void snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv)204{205 driver_unregister(&drv->driver);206}207EXPORT_SYMBOL_GPL(snd_ac97_codec_driver_unregister);208 209/**210 * snd_ac97_codec_get_platdata - get platform_data211 * @adev: the ac97 codec device212 *213 * For legacy platforms, in order to have platform_data in codec drivers214 * available, while ac97 device are auto-created upon probe, this retrieves the215 * platdata which was setup on ac97 controller registration.216 *217 * Returns the platform data pointer218 */219void *snd_ac97_codec_get_platdata(const struct ac97_codec_device *adev)220{221 struct ac97_controller *ac97_ctrl = adev->ac97_ctrl;222 223 return ac97_ctrl->codecs_pdata[adev->num];224}225EXPORT_SYMBOL_GPL(snd_ac97_codec_get_platdata);226 227static void ac97_ctrl_codecs_unregister(struct ac97_controller *ac97_ctrl)228{229 int i;230 231 for (i = 0; i < AC97_BUS_MAX_CODECS; i++)232 if (ac97_ctrl->codecs[i]) {233 ac97_ctrl->codecs[i]->ac97_ctrl = &ac97_unbound_ctrl;234 device_unregister(&ac97_ctrl->codecs[i]->dev);235 }236}237 238static ssize_t cold_reset_store(struct device *dev,239 struct device_attribute *attr, const char *buf,240 size_t len)241{242 struct ac97_controller *ac97_ctrl;243 244 mutex_lock(&ac97_controllers_mutex);245 ac97_ctrl = to_ac97_controller(dev);246 ac97_ctrl->ops->reset(ac97_ctrl);247 mutex_unlock(&ac97_controllers_mutex);248 return len;249}250static DEVICE_ATTR_WO(cold_reset);251 252static ssize_t warm_reset_store(struct device *dev,253 struct device_attribute *attr, const char *buf,254 size_t len)255{256 struct ac97_controller *ac97_ctrl;257 258 if (!dev)259 return -ENODEV;260 261 mutex_lock(&ac97_controllers_mutex);262 ac97_ctrl = to_ac97_controller(dev);263 ac97_ctrl->ops->warm_reset(ac97_ctrl);264 mutex_unlock(&ac97_controllers_mutex);265 return len;266}267static DEVICE_ATTR_WO(warm_reset);268 269static struct attribute *ac97_controller_device_attrs[] = {270 &dev_attr_cold_reset.attr,271 &dev_attr_warm_reset.attr,272 NULL273};274 275static const struct attribute_group ac97_adapter_attr_group = {276 .name = "ac97_operations",277 .attrs = ac97_controller_device_attrs,278};279 280static const struct attribute_group *ac97_adapter_groups[] = {281 &ac97_adapter_attr_group,282 NULL,283};284 285static void ac97_del_adapter(struct ac97_controller *ac97_ctrl)286{287 mutex_lock(&ac97_controllers_mutex);288 ac97_ctrl_codecs_unregister(ac97_ctrl);289 list_del(&ac97_ctrl->controllers);290 mutex_unlock(&ac97_controllers_mutex);291 292 device_unregister(&ac97_ctrl->adap);293}294 295static void ac97_adapter_release(struct device *dev)296{297 struct ac97_controller *ac97_ctrl;298 299 ac97_ctrl = to_ac97_controller(dev);300 idr_remove(&ac97_adapter_idr, ac97_ctrl->nr);301 dev_dbg(&ac97_ctrl->adap, "adapter unregistered by %s\n",302 dev_name(ac97_ctrl->parent));303}304 305static const struct device_type ac97_adapter_type = {306 .groups = ac97_adapter_groups,307 .release = ac97_adapter_release,308};309 310static int ac97_add_adapter(struct ac97_controller *ac97_ctrl)311{312 int ret;313 314 mutex_lock(&ac97_controllers_mutex);315 ret = idr_alloc(&ac97_adapter_idr, ac97_ctrl, 0, 0, GFP_KERNEL);316 ac97_ctrl->nr = ret;317 if (ret >= 0) {318 dev_set_name(&ac97_ctrl->adap, "ac97-%d", ret);319 ac97_ctrl->adap.type = &ac97_adapter_type;320 ac97_ctrl->adap.parent = ac97_ctrl->parent;321 ret = device_register(&ac97_ctrl->adap);322 if (ret)323 put_device(&ac97_ctrl->adap);324 }325 if (!ret)326 list_add(&ac97_ctrl->controllers, &ac97_controllers);327 mutex_unlock(&ac97_controllers_mutex);328 329 if (!ret)330 dev_dbg(&ac97_ctrl->adap, "adapter registered by %s\n",331 dev_name(ac97_ctrl->parent));332 return ret;333}334 335/**336 * snd_ac97_controller_register - register an ac97 controller337 * @ops: the ac97 bus operations338 * @dev: the device providing the ac97 DC function339 * @slots_available: mask of the ac97 codecs that can be scanned and probed340 * bit0 => codec 0, bit1 => codec 1 ... bit 3 => codec 3341 *342 * Register a digital controller which can control up to 4 ac97 codecs. This is343 * the controller side of the AC97 AC-link, while the slave side are the codecs.344 *345 * Returns a valid controller upon success, negative pointer value upon error346 */347struct ac97_controller *snd_ac97_controller_register(348 const struct ac97_controller_ops *ops, struct device *dev,349 unsigned short slots_available, void **codecs_pdata)350{351 struct ac97_controller *ac97_ctrl;352 int ret, i;353 354 ac97_ctrl = kzalloc(sizeof(*ac97_ctrl), GFP_KERNEL);355 if (!ac97_ctrl)356 return ERR_PTR(-ENOMEM);357 358 for (i = 0; i < AC97_BUS_MAX_CODECS && codecs_pdata; i++)359 ac97_ctrl->codecs_pdata[i] = codecs_pdata[i];360 361 ac97_ctrl->ops = ops;362 ac97_ctrl->slots_available = slots_available;363 ac97_ctrl->parent = dev;364 ret = ac97_add_adapter(ac97_ctrl);365 366 if (ret)367 goto err;368 ac97_bus_reset(ac97_ctrl);369 ac97_bus_scan(ac97_ctrl);370 371 return ac97_ctrl;372err:373 kfree(ac97_ctrl);374 return ERR_PTR(ret);375}376EXPORT_SYMBOL_GPL(snd_ac97_controller_register);377 378/**379 * snd_ac97_controller_unregister - unregister an ac97 controller380 * @ac97_ctrl: the device previously provided to ac97_controller_register()381 *382 */383void snd_ac97_controller_unregister(struct ac97_controller *ac97_ctrl)384{385 ac97_del_adapter(ac97_ctrl);386}387EXPORT_SYMBOL_GPL(snd_ac97_controller_unregister);388 389#ifdef CONFIG_PM390static int ac97_pm_runtime_suspend(struct device *dev)391{392 struct ac97_codec_device *codec = to_ac97_device(dev);393 int ret = pm_generic_runtime_suspend(dev);394 395 if (ret == 0 && dev->driver) {396 if (pm_runtime_is_irq_safe(dev))397 clk_disable(codec->clk);398 else399 clk_disable_unprepare(codec->clk);400 }401 402 return ret;403}404 405static int ac97_pm_runtime_resume(struct device *dev)406{407 struct ac97_codec_device *codec = to_ac97_device(dev);408 int ret;409 410 if (dev->driver) {411 if (pm_runtime_is_irq_safe(dev))412 ret = clk_enable(codec->clk);413 else414 ret = clk_prepare_enable(codec->clk);415 if (ret)416 return ret;417 }418 419 return pm_generic_runtime_resume(dev);420}421#endif /* CONFIG_PM */422 423static const struct dev_pm_ops ac97_pm = {424 .suspend = pm_generic_suspend,425 .resume = pm_generic_resume,426 .freeze = pm_generic_freeze,427 .thaw = pm_generic_thaw,428 .poweroff = pm_generic_poweroff,429 .restore = pm_generic_restore,430 SET_RUNTIME_PM_OPS(431 ac97_pm_runtime_suspend,432 ac97_pm_runtime_resume,433 NULL)434};435 436static int ac97_get_enable_clk(struct ac97_codec_device *adev)437{438 int ret;439 440 adev->clk = clk_get(&adev->dev, "ac97_clk");441 if (IS_ERR(adev->clk))442 return PTR_ERR(adev->clk);443 444 ret = clk_prepare_enable(adev->clk);445 if (ret)446 clk_put(adev->clk);447 448 return ret;449}450 451static void ac97_put_disable_clk(struct ac97_codec_device *adev)452{453 clk_disable_unprepare(adev->clk);454 clk_put(adev->clk);455}456 457static ssize_t vendor_id_show(struct device *dev,458 struct device_attribute *attr, char *buf)459{460 struct ac97_codec_device *codec = to_ac97_device(dev);461 462 return sysfs_emit(buf, "%08x", codec->vendor_id);463}464static DEVICE_ATTR_RO(vendor_id);465 466static struct attribute *ac97_dev_attrs[] = {467 &dev_attr_vendor_id.attr,468 NULL,469};470ATTRIBUTE_GROUPS(ac97_dev);471 472static int ac97_bus_match(struct device *dev, const struct device_driver *drv)473{474 struct ac97_codec_device *adev = to_ac97_device(dev);475 const struct ac97_codec_driver *adrv = to_ac97_driver(drv);476 const struct ac97_id *id = adrv->id_table;477 int i = 0;478 479 if (adev->vendor_id == 0x0 || adev->vendor_id == 0xffffffff)480 return false;481 482 do {483 if (ac97_ids_match(id[i].id, adev->vendor_id, id[i].mask))484 return true;485 } while (id[i++].id);486 487 return false;488}489 490static int ac97_bus_probe(struct device *dev)491{492 struct ac97_codec_device *adev = to_ac97_device(dev);493 struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);494 int ret;495 496 ret = ac97_get_enable_clk(adev);497 if (ret)498 return ret;499 500 pm_runtime_get_noresume(dev);501 pm_runtime_set_active(dev);502 pm_runtime_enable(dev);503 504 ret = adrv->probe(adev);505 if (ret == 0)506 return 0;507 508 pm_runtime_disable(dev);509 pm_runtime_set_suspended(dev);510 pm_runtime_put_noidle(dev);511 ac97_put_disable_clk(adev);512 513 return ret;514}515 516static void ac97_bus_remove(struct device *dev)517{518 struct ac97_codec_device *adev = to_ac97_device(dev);519 struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);520 int ret;521 522 ret = pm_runtime_resume_and_get(dev);523 if (ret < 0)524 return;525 526 adrv->remove(adev);527 pm_runtime_put_noidle(dev);528 ac97_put_disable_clk(adev);529 530 pm_runtime_disable(dev);531}532 533const struct bus_type ac97_bus_type = {534 .name = "ac97bus",535 .dev_groups = ac97_dev_groups,536 .match = ac97_bus_match,537 .pm = &ac97_pm,538 .probe = ac97_bus_probe,539 .remove = ac97_bus_remove,540};541 542static int __init ac97_bus_init(void)543{544 return bus_register(&ac97_bus_type);545}546subsys_initcall(ac97_bus_init);547 548static void __exit ac97_bus_exit(void)549{550 bus_unregister(&ac97_bus_type);551}552module_exit(ac97_bus_exit);553 554MODULE_DESCRIPTION("AC97 bus interface");555MODULE_LICENSE("GPL");556MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");557