100 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Linux driver model AC97 bus interface4 *5 * Author: Nicolas Pitre6 * Created: Jan 14, 20057 * Copyright: (C) MontaVista Software Inc.8 */9 10#include <linux/module.h>11#include <linux/init.h>12#include <linux/device.h>13#include <linux/string.h>14#include <sound/ac97_codec.h>15 16/*17 * snd_ac97_check_id() - Reads and checks the vendor ID of the device18 * @ac97: The AC97 device to check19 * @id: The ID to compare to20 * @id_mask: Mask that is applied to the device ID before comparing to @id21 *22 * If @id is 0 this function returns true if the read device vendor ID is23 * a valid ID. If @id is non 0 this functions returns true if @id24 * matches the read vendor ID. Otherwise the function returns false.25 */26static bool snd_ac97_check_id(struct snd_ac97 *ac97, unsigned int id,27 unsigned int id_mask)28{29 ac97->id = ac97->bus->ops->read(ac97, AC97_VENDOR_ID1) << 16;30 ac97->id |= ac97->bus->ops->read(ac97, AC97_VENDOR_ID2);31 32 if (ac97->id == 0x0 || ac97->id == 0xffffffff)33 return false;34 35 if (id != 0 && id != (ac97->id & id_mask))36 return false;37 38 return true;39}40 41/**42 * snd_ac97_reset() - Reset AC'97 device43 * @ac97: The AC'97 device to reset44 * @try_warm: Try a warm reset first45 * @id: Expected device vendor ID46 * @id_mask: Mask that is applied to the device ID before comparing to @id47 *48 * This function resets the AC'97 device. If @try_warm is true the function49 * first performs a warm reset. If the warm reset is successful the function50 * returns 1. Otherwise or if @try_warm is false the function issues cold reset51 * followed by a warm reset. If this is successful the function returns 0,52 * otherwise a negative error code. If @id is 0 any valid device ID will be53 * accepted, otherwise only the ID that matches @id and @id_mask is accepted.54 */55int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,56 unsigned int id_mask)57{58 const struct snd_ac97_bus_ops *ops = ac97->bus->ops;59 60 if (try_warm && ops->warm_reset) {61 ops->warm_reset(ac97);62 if (snd_ac97_check_id(ac97, id, id_mask))63 return 1;64 }65 66 if (ops->reset)67 ops->reset(ac97);68 if (ops->warm_reset)69 ops->warm_reset(ac97);70 71 if (snd_ac97_check_id(ac97, id, id_mask))72 return 0;73 74 return -ENODEV;75}76EXPORT_SYMBOL_GPL(snd_ac97_reset);77 78const struct bus_type ac97_bus_type = {79 .name = "ac97",80};81 82static int __init ac97_bus_init(void)83{84 return bus_register(&ac97_bus_type);85}86 87subsys_initcall(ac97_bus_init);88 89static void __exit ac97_bus_exit(void)90{91 bus_unregister(&ac97_bus_type);92}93 94module_exit(ac97_bus_exit);95 96EXPORT_SYMBOL(ac97_bus_type);97 98MODULE_DESCRIPTION("Legacy AC97 bus interface");99MODULE_LICENSE("GPL");100