Skip to content

Commit 74426fb

Browse files
rjarzmikbroonie
authored andcommitted
ALSA: ac97: add an ac97 bus
AC97 is a bus for sound usage. It enables for a AC97 AC-Link to link one controller to 0 to 4 AC97 codecs. The goal of this new implementation is to implement a device/driver model for AC97, with an automatic scan of the bus and automatic discovery of AC97 codec devices. Signed-off-by: Robert Jarzmik <[email protected]> Reviewed-by: Takashi Iwai <[email protected]> Signed-off-by: Mark Brown <[email protected]>
1 parent 8e4f7d9 commit 74426fb

File tree

9 files changed

+928
-0
lines changed

9 files changed

+928
-0
lines changed

include/sound/ac97/codec.h

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Copyright (C) 2016 Robert Jarzmik <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License version 2 as
6+
* published by the Free Software Foundation.
7+
*/
8+
#ifndef __SOUND_AC97_CODEC2_H
9+
#define __SOUND_AC97_CODEC2_H
10+
11+
#include <linux/device.h>
12+
13+
#define AC97_ID(vendor_id1, vendor_id2) \
14+
((((vendor_id1) & 0xffff) << 16) | ((vendor_id2) & 0xffff))
15+
#define AC97_DRIVER_ID(vendor_id1, vendor_id2, mask_id1, mask_id2, _data) \
16+
{ .id = (((vendor_id1) & 0xffff) << 16) | ((vendor_id2) & 0xffff), \
17+
.mask = (((mask_id1) & 0xffff) << 16) | ((mask_id2) & 0xffff), \
18+
.data = (_data) }
19+
20+
struct ac97_controller;
21+
struct clk;
22+
23+
/**
24+
* struct ac97_id - matches a codec device and driver on an ac97 bus
25+
* @id: The significant bits if the codec vendor ID1 and ID2
26+
* @mask: Bitmask specifying which bits of the id field are significant when
27+
* matching. A driver binds to a device when :
28+
* ((vendorID1 << 8 | vendorID2) & (mask_id1 << 8 | mask_id2)) == id.
29+
* @data: Private data used by the driver.
30+
*/
31+
struct ac97_id {
32+
unsigned int id;
33+
unsigned int mask;
34+
void *data;
35+
};
36+
37+
/**
38+
* ac97_codec_device - a ac97 codec
39+
* @dev: the core device
40+
* @vendor_id: the vendor_id of the codec, as sensed on the AC-link
41+
* @num: the codec number, 0 is primary, 1 is first slave, etc ...
42+
* @clk: the clock BIT_CLK provided by the codec
43+
* @ac97_ctrl: ac97 digital controller on the same AC-link
44+
*
45+
* This is the device instantiated for each codec living on a AC-link. There are
46+
* normally 0 to 4 codec devices per AC-link, and all of them are controlled by
47+
* an AC97 digital controller.
48+
*/
49+
struct ac97_codec_device {
50+
struct device dev;
51+
unsigned int vendor_id;
52+
unsigned int num;
53+
struct clk *clk;
54+
struct ac97_controller *ac97_ctrl;
55+
};
56+
57+
/**
58+
* ac97_codec_driver - a ac97 codec driver
59+
* @driver: the device driver structure
60+
* @probe: the function called when a ac97_codec_device is matched
61+
* @remove: the function called when the device is unbound/removed
62+
* @shutdown: shutdown function (might be NULL)
63+
* @id_table: ac97 vendor_id match table, { } member terminated
64+
*/
65+
struct ac97_codec_driver {
66+
struct device_driver driver;
67+
int (*probe)(struct ac97_codec_device *);
68+
int (*remove)(struct ac97_codec_device *);
69+
void (*shutdown)(struct ac97_codec_device *);
70+
const struct ac97_id *id_table;
71+
};
72+
73+
static inline struct ac97_codec_device *to_ac97_device(struct device *d)
74+
{
75+
return container_of(d, struct ac97_codec_device, dev);
76+
}
77+
78+
static inline struct ac97_codec_driver *to_ac97_driver(struct device_driver *d)
79+
{
80+
return container_of(d, struct ac97_codec_driver, driver);
81+
}
82+
83+
#if IS_ENABLED(CONFIG_AC97_BUS_NEW)
84+
int snd_ac97_codec_driver_register(struct ac97_codec_driver *drv);
85+
void snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv);
86+
#else
87+
static inline int
88+
snd_ac97_codec_driver_register(struct ac97_codec_driver *drv)
89+
{
90+
return 0;
91+
}
92+
static inline void
93+
snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv)
94+
{
95+
}
96+
#endif
97+
98+
99+
static inline struct device *
100+
ac97_codec_dev2dev(struct ac97_codec_device *adev)
101+
{
102+
return &adev->dev;
103+
}
104+
105+
static inline void *ac97_get_drvdata(struct ac97_codec_device *adev)
106+
{
107+
return dev_get_drvdata(ac97_codec_dev2dev(adev));
108+
}
109+
110+
static inline void ac97_set_drvdata(struct ac97_codec_device *adev,
111+
void *data)
112+
{
113+
dev_set_drvdata(ac97_codec_dev2dev(adev), data);
114+
}
115+
116+
void *snd_ac97_codec_get_platdata(const struct ac97_codec_device *adev);
117+
118+
#endif

include/sound/ac97/compat.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (C) 2016 Robert Jarzmik <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License version 2 as
6+
* published by the Free Software Foundation.
7+
*
8+
* This file is for backward compatibility with snd_ac97 structure and its
9+
* multiple usages, such as the snd_ac97_bus and snd_ac97_build_ops.
10+
*
11+
*/
12+
#ifndef AC97_COMPAT_H
13+
#define AC97_COMPAT_H
14+
15+
#include <sound/ac97_codec.h>
16+
17+
struct snd_ac97 *snd_ac97_compat_alloc(struct ac97_codec_device *adev);
18+
void snd_ac97_compat_release(struct snd_ac97 *ac97);
19+
20+
#endif

include/sound/ac97/controller.h

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (C) 2016 Robert Jarzmik <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License version 2 as
6+
* published by the Free Software Foundation.
7+
*/
8+
#ifndef AC97_CONTROLLER_H
9+
#define AC97_CONTROLLER_H
10+
11+
#include <linux/device.h>
12+
#include <linux/list.h>
13+
14+
#define AC97_BUS_MAX_CODECS 4
15+
#define AC97_SLOTS_AVAILABLE_ALL 0xf
16+
17+
struct ac97_controller_ops;
18+
19+
/**
20+
* struct ac97_controller - The AC97 controller of the AC-Link
21+
* @ops: the AC97 operations.
22+
* @controllers: linked list of all existing controllers.
23+
* @adap: the shell device ac97-%d, ie. ac97 adapter
24+
* @nr: the number of the shell device
25+
* @slots_available: the mask of accessible/scanable codecs.
26+
* @parent: the device providing the AC97 controller.
27+
* @codecs: the 4 possible AC97 codecs (NULL if none found).
28+
* @codecs_pdata: platform_data for each codec (NULL if no pdata).
29+
*
30+
* This structure is internal to AC97 bus, and should not be used by the
31+
* controllers themselves, excepting for using @dev.
32+
*/
33+
struct ac97_controller {
34+
const struct ac97_controller_ops *ops;
35+
struct list_head controllers;
36+
struct device adap;
37+
int nr;
38+
unsigned short slots_available;
39+
struct device *parent;
40+
struct ac97_codec_device *codecs[AC97_BUS_MAX_CODECS];
41+
void *codecs_pdata[AC97_BUS_MAX_CODECS];
42+
};
43+
44+
/**
45+
* struct ac97_controller_ops - The AC97 operations
46+
* @reset: Cold reset of the AC97 AC-Link.
47+
* @warm_reset: Warm reset of the AC97 AC-Link.
48+
* @read: Read of a single AC97 register.
49+
* Returns the register value or a negative error code.
50+
* @write: Write of a single AC97 register.
51+
*
52+
* These are the basic operation an AC97 controller must provide for an AC97
53+
* access functions. Amongst these, all but the last 2 are mandatory.
54+
* The slot number is also known as the AC97 codec number, between 0 and 3.
55+
*/
56+
struct ac97_controller_ops {
57+
void (*reset)(struct ac97_controller *adrv);
58+
void (*warm_reset)(struct ac97_controller *adrv);
59+
int (*write)(struct ac97_controller *adrv, int slot,
60+
unsigned short reg, unsigned short val);
61+
int (*read)(struct ac97_controller *adrv, int slot, unsigned short reg);
62+
};
63+
64+
#if IS_ENABLED(CONFIG_AC97_BUS_NEW)
65+
struct ac97_controller *snd_ac97_controller_register(
66+
const struct ac97_controller_ops *ops, struct device *dev,
67+
unsigned short slots_available, void **codecs_pdata);
68+
void snd_ac97_controller_unregister(struct ac97_controller *ac97_ctrl);
69+
#else
70+
static inline struct ac97_controller *
71+
snd_ac97_controller_register(const struct ac97_controller_ops *ops,
72+
struct device *dev,
73+
unsigned short slots_available,
74+
void **codecs_pdata)
75+
{
76+
return ERR_PTR(-ENODEV);
77+
}
78+
79+
static inline void
80+
snd_ac97_controller_unregister(struct ac97_controller *ac97_ctrl)
81+
{
82+
}
83+
#endif
84+
85+
#endif

sound/ac97/Kconfig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#
2+
# AC97 configuration
3+
#
4+
5+
6+
config AC97_BUS_NEW
7+
tristate
8+
select AC97
9+
help
10+
This is the new AC97 bus type, successor of AC97_BUS. The ported
11+
drivers which benefit from the AC97 automatic probing should "select"
12+
this instead of the AC97_BUS.
13+
Say Y here if you want to have AC97 devices, which are sound oriented
14+
devices around an AC-Link.
15+
16+
config AC97_BUS_COMPAT
17+
bool
18+
depends on AC97_BUS_NEW
19+
depends on !AC97_BUS

sound/ac97/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#
2+
# make for AC97 bus drivers
3+
#
4+
5+
obj-$(CONFIG_AC97_BUS_NEW) += ac97.o
6+
7+
ac97-y += bus.o codec.o
8+
ac97-$(CONFIG_AC97_BUS_COMPAT) += snd_ac97_compat.o

sound/ac97/ac97_core.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright (C) 2016 Robert Jarzmik <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License version 2 as
6+
* published by the Free Software Foundation.
7+
*/
8+
9+
unsigned int snd_ac97_bus_scan_one(struct ac97_controller *ac97,
10+
unsigned int codec_num);
11+
12+
static inline bool ac97_ids_match(unsigned int id1, unsigned int id2,
13+
unsigned int mask)
14+
{
15+
return (id1 & mask) == (id2 & mask);
16+
}

0 commit comments

Comments
 (0)