Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
January 2017
- 145 participants
- 274 discussions
[alsa-devel] [Alsa-Devel] Cannot combine audio devices with more than 64 channels
by Jörg Müller 31 Jan '17
by Jörg Müller 31 Jan '17
31 Jan '17
I need to combine two HDSPe MADI FX cards to one virtual device. I
have a working driver, which is alsa-compatible. I can select each
single card in any alsa-compatible application and all channels work
flawless.
For combining the MADI FX cards to one virtual device, I created an
.asoundrc with 194 inputs for each card. When I start that virtual
device via
jackd -R -d alsa -C madifx_record_all -P madifx_playback_all
I get this error:
> creating alsa driver ...
> madifx_playback_all|madifx_record_all|1024|2|48000|0|0|nomon|swmeter|-|32bit
> jackd: pcm_multi.c:1060: snd_pcm_multi_open: Assertion `!slave_map[sidxs[i]][schannels[i]]' failed.
However, it works when I reduce the amount from 194 to 64 channels per
card. I tried to use 128 channels per card, but that fails the same
way. See my alsa-info here http://pastebin.com/4hq1B3wZ , which also
includes the .asoundrc content.
I also found this, which might be related:
https://ccrma.stanford.edu/mirrors/lalists/lad/2005/06/0202.html
To me, this looks like a bug. What do you think?
For reference, I posted the same question on
http://lists.jackaudio.org/private.cgi/jack-devel-jackaudio.org/2017-Januar…,
however, they recommended to ask here for help.
5
11
[alsa-devel] [PATCH v6 0/3] Add support for es8388 and hdmi audio on the rock2
by Romain Perier 31 Jan '17
by Romain Perier 31 Jan '17
31 Jan '17
This set of patches adds a machine driver for rk3288-based boards that have
the built-in HDMI audio and a generic analog output. It also adds slave mode
to the es8328 driver that currently only supported the master mode. Then, it
adds the required DT definitions to link rockchip-i2s to the es8388 analog
output and to hdmi audio.
This work is based on the initial work that was done by Sjoerd Simons
<sjoerd.simons(a)collabora.co.uk> with some improvements, changes and more
commits.
Changes in v6:
- Fixed bad error handling for gpio in rk3288_analog_hdmi.c
- Removed message duplication in rk_hw_params(), in rk3288_analog_hdmi.c
- Removed patch 1/4 (from the previous series), as it has been merged
Changes in v5:
- Fixed coding style issue in patch 2/4 (the switch case).
- Moved the code for the master mode and the slave mode into the switch case for patch 2/4
- Fixed error handling for patch 3/4
Changes in v4:
- Add support for multi codecs in the asoc machine driver, so the driver
matches the hw architecture (analog and hdmi audio are connected on
the same i2s line)
- Renamed the driver to rk3288-hdmi-analog.c and changed its
documentation
- Add built-in support for hdmi audio in this driver
- Add support for the property 'rockchip,routing'
Changes in v3:
- Cosmetic changes in rockchip_es8388.c
- Added missing email to MODULE_AUTHOR in rockchip_es8388.c
Changes in v2:
- Fixed wrong use of the data structure i2c_device_id
- Fixed wrong dependencies for SND_SOC_ROCKCHIP_ES8388
Romain Perier (3):
ASoC: es8328: Add support for slave mode
ASoC: rockchip: Add machine driver for RK3288 boards that use
analog/HDMI
arm: dts: Add support for ES8388 to the Radxa Rock 2
.../bindings/sound/rockchip,rk3288-hdmi-analog.txt | 36 +++
arch/arm/boot/dts/rk3288-rock2-square.dts | 39 +++
sound/soc/codecs/es8328.c | 20 +-
sound/soc/rockchip/Kconfig | 10 +
sound/soc/rockchip/Makefile | 2 +
sound/soc/rockchip/rk3288_hdmi_analog.c | 299 +++++++++++++++++++++
6 files changed, 400 insertions(+), 6 deletions(-)
create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3288-hdmi-analog.txt
create mode 100644 sound/soc/rockchip/rk3288_hdmi_analog.c
--
2.9.3
2
5
31 Jan '17
I will keep this brief.
When things get to the point where every post one makes to alsa-devel is
responded to with personal attacks, disdain, contempt or hostility, where
one's extensive practical and technical experience is dismissed as being
invalid at every opportunity, and one is consequently anxious about reading
the responses to one's posts in alsa-devel, it's clearly time to walk away.
Sadly, this is the situation I find myself in so walking away is what I will
do once this message has been posted.
Moving firewire audio streaming functionality into the kernel has been a
long term goal of the FFADO project. Having a decade of experience working
successfully with these devices under Linux through FFADO and its
predecessors, I was planning to lend assistance to the ALSA firewire
streaming driver development effort. Unfortunately, it has become
abundantly clear that for some reason this is not welcomed (or even
tolerated) by some, so instead I will devote my time to the maintenance of
FFADO and my other Open Source projects.
Although *extremely* miniscule in comparison to the deplorable harassment
directed toward others in the Open Source community in the past, the
treatment I have received has given me a fresh perspective on the effect
that continued attacks can have on a person's attitude to life, and why many
good developers have completely turned their back on the entire Open Source
movement when faced with these kinds of issues. The Open Source community
has wonderfully awesome people, but it is clear how the misdirected actions
of a few can so easily drive people away.
I wish the ALSA project well for its future work, and urge project members
to treat all participants with the basic human rights of respect and dignity
which were not afforded to me over the past two years on alsa-devel.
Regards
jonathan
3
2
For two or three kernel versions of alsa divers now, HDMI has been the default alsa device on my laptop (Dell Latitude E7240) - this does not make logical sense.
In the latest kernel version I use, 4.2.9, alsa sound will not work at all unless I load the i915 kernel driver - this does not make logical sense and means that I cannot use Xvesa.
Is it possible to make an alsa feature request for analogue sound to be the default alsa device on laptops and for alsa sound to work without the need to load the i915 kernel driver?
Regards
John
**** List of PLAYBACK Hardware Devices ****
card 0: HDMI [HDA Intel HDMI], device 3: HDMI 0 [HDMI 0]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 7: HDMI 1 [HDMI 1]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 8: HDMI 2 [HDMI 2]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 1: PCH [HDA Intel PCH], device 0: ALC3226 Analog [ALC3226 Analog]
Subdevices: 1/1
Subdevice #0: subdevice #0
4
23
[alsa-devel] workqueue lockup due to process_unsol_events stuck in azx_rirb_get_response
by Vlastimil Babka 31 Jan '17
by Vlastimil Babka 31 Jan '17
31 Jan '17
Hi,
my desktop randomly experiences workqueue lockups on boot with openSUSE
Tumbleweed kernels 4.9.x, installed around Christmas. Previously I had a (badly
maintained) Gentoo installation with 4.4 IIRC, so I can't say if the kernel has
regressed, or the major userspace changes exposed different timing of stuff.
This is how the workqueue lockup looks like:
kernel: BUG: workqueue lockup - pool cpus=3 node=0 flags=0x0 nice=0 stuck for 173s!
kernel: Showing busy workqueues and worker pools:
kernel: workqueue events: flags=0x0
kernel: pwq 6: cpus=3 node=0 flags=0x0 nice=0 active=9/256
kernel: in-flight: 60:process_unsol_events [snd_hda_core]
process_unsol_events [snd_hda_core]
kernel: pending: dbs_work_handler, push_to_pool, vmstat_shepherd,
cache_reap, console_callback, sysrq_reinject_alt_sysrq, check_corrup
kernel: workqueue events_power_efficient: flags=0x80
kernel: pwq 6: cpus=3 node=0 flags=0x0 nice=0 active=1/256
kernel: pending: neigh_periodic_work
kernel: workqueue lru-add-drain: flags=0x8
kernel: pwq 6: cpus=3 node=0 flags=0x0 nice=0 active=1/256
kernel: pending: lru_add_drain_per_cpu BAR(1161)
kernel: workqueue vmstat: flags=0xc
kernel: pwq 6: cpus=3 node=0 flags=0x0 nice=0 active=1/256
kernel: pending: vmstat_update
kernel: workqueue ipv6_addrconf: flags=0x40008
kernel: pwq 6: cpus=3 node=0 flags=0x0 nice=0 active=1/1
kernel: pending: addrconf_verify_work
kernel: pool 6: cpus=3 node=0 flags=0x0 nice=0 hung=173s workers=4 idle: 134 373 30
This prevented me from getting a login prompt, as systemd is waiting for wicked.
I have used sysrq to list the stuck tasks:
kernel: sysrq: SysRq : Show Blocked State
kernel: task PC stack pid father
kernel: wickedd-nanny D 0 1161 1 0x00000000
kernel: ffff9f88e3ebc000 0000000000000000 ffff9f88e3506040 ffff9f88efd59780
kernel: ffff9f883ee90100 ffffb2dc81117d28 ffffffffa9715ff6 ffff9f88efd59780
kernel: 00ffb2dc81117d20 ffff9f88efd59780 ffff9f88def44000 ffff9f88e3506040
kernel: Call Trace:
kernel: [<ffffffffa9715ff6>] ? __schedule+0x236/0x700
kernel: [<ffffffffa97164fd>] schedule+0x3d/0x90
kernel: [<ffffffffa971984e>] schedule_timeout+0x22e/0x410
kernel: [<ffffffffa90ab6e8>] ? finish_task_switch+0x78/0x1f0
kernel: [<ffffffffa90af94a>] ? try_to_wake_up+0x4a/0x3d0
kernel: [<ffffffffa9717837>] wait_for_completion+0x97/0x100
kernel: [<ffffffffa90afd70>] ? wake_up_q+0x80/0x80
kernel: [<ffffffffa909d747>] flush_work+0xf7/0x190
kernel: [<ffffffffa909b370>] ? flush_workqueue_prep_pwqs+0x1a0/0x1a0
kernel: [<ffffffffa91b4191>] lru_add_drain_all+0x121/0x160
kernel: [<ffffffffa91ddc15>] do_mlock+0x45/0x230
kernel: [<ffffffffa91ddf33>] SyS_mlock+0x13/0x20
kernel: [<ffffffffa971b47b>] entry_SYSCALL_64_fastpath+0x1e/0xad
Yep, stuck waiting for work item completion, but workqueue processing on cpu 3
is stuck (and contains such item).
Then I listed backtraces of all active CPU's:
kernel: sysrq: SysRq : Show backtrace of all active CPUs
kernel: NMI backtrace for cpu 3
kernel: CPU: 3 PID: 60 Comm: kworker/3:1 Not tainted 4.9.3-1-default #1
kernel: Hardware name: Gigabyte Technology Co., Ltd. GA-870A-UD3/GA-870A-UD3,
BIOS F5 08/01/2011
kernel: Workqueue: events process_unsol_events [snd_hda_core]
kernel: ffff9f88efcc3a90 ffffffffa93c4f70 0000000000000000 0000000000000003
kernel: ffff9f88efcc3ac0 ffffffffa93c8e44 ffffffffa9055c80 0000000000000003
kernel: 0000000000000001 ffffffffa9cc43c0 ffff9f88efcc3ae0 ffffffffa93c8f66
kernel: Call Trace:
kernel: <IRQ>
kernel: [<ffffffffa93c4f70>] dump_stack+0x63/0x83
kernel: [<ffffffffa93c8e44>] nmi_cpu_backtrace+0x94/0xa0
kernel: [<ffffffffa9055c80>] ? irq_force_complete_move+0x150/0x150
kernel: [<ffffffffa93c8f66>] nmi_trigger_cpumask_backtrace+0x116/0x150
kernel: [<ffffffffa9055cf9>] arch_trigger_cpumask_backtrace+0x19/0x20
kernel: [<ffffffffa94ce877>] sysrq_handle_showallcpus+0x17/0x20
kernel: [<ffffffffa94cef1b>] __handle_sysrq+0xfb/0x150
[ snip keyboard event processing ]
kernel: [<ffffffffa903128d>] handle_irq+0x1d/0x30
kernel: [<ffffffffa971ddab>] do_IRQ+0x4b/0xd0
kernel: [<ffffffffa971be02>] common_interrupt+0x82/0x82
kernel: <EOI>
kernel: [<ffffffffa93d1ef3>] ? delay_tsc+0x43/0x90
kernel: [<ffffffffa93d1e2d>] __const_udelay+0x2d/0x30
kernel: [<ffffffffc0c08403>] azx_rirb_get_response+0xb3/0x280 [snd_hda_codec]
kernel: [<ffffffffc0c08b43>] azx_get_response+0x33/0x40 [snd_hda_codec]
kernel: [<ffffffffc0b86303>] snd_hdac_bus_exec_verb_unlocked+0x83/0x170
[snd_hda_core]
kernel: [<ffffffffa952e85c>] ? __pm_runtime_resume+0x4c/0x60
kernel: [<ffffffffc0bfe4fa>] codec_exec_verb+0x8a/0x110 [snd_hda_codec]
kernel: [<ffffffffc0b86f97>] snd_hdac_exec_verb+0x17/0x40 [snd_hda_core]
kernel: [<ffffffffc0b87944>] snd_hdac_codec_read+0x34/0x50 [snd_hda_core]
kernel: [<ffffffffc0c20501>] dspio_read+0x51/0x70 [snd_hda_codec_ca0132]
kernel: [<ffffffffc0c20566>] ca0132_process_dsp_response+0x46/0x160
[snd_hda_codec_ca0132]
kernel: [<ffffffffc0c02fe5>] call_jack_callback.isra.1+0x25/0xa0 [snd_hda_codec]
kernel: [<ffffffffc0c033c6>] snd_hda_jack_unsol_event+0x66/0x80 [snd_hda_codec]
kernel: [<ffffffffc0bfd077>] hda_codec_unsol_event+0x17/0x20 [snd_hda_codec]
kernel: [<ffffffffc0b86193>] process_unsol_events+0x63/0x70 [snd_hda_core]
kernel: [<ffffffffa909e4d3>] process_one_work+0x1f3/0x4d0
kernel: [<ffffffffa909e7f8>] worker_thread+0x48/0x4e0
kernel: [<ffffffffa909e7b0>] ? process_one_work+0x4d0/0x4d0
kernel: [<ffffffffa909e7b0>] ? process_one_work+0x4d0/0x4d0
kernel: [<ffffffffa90a46da>] kthread+0xca/0xe0
kernel: [<ffffffffa90a4610>] ? kthread_park+0x60/0x60
kernel: [<ffffffffa971b6f5>] ret_from_fork+0x25/0x30
This backtrace looks stable on multiple retries. I've rebooted and added
module_blacklist=snd_hda_core on the command line to work around this for now.
Here's the relevant lspci. The card I use right now is an onboard audio with 3
output jacks for 5.1. The Creative Audigy is currently unused, as should be the
HDMI stuff.
00:14.2 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] SBx00 Azalia (Intel
HDA) (rev 40)
Subsystem: Gigabyte Technology Co., Ltd Device a102
Flags: bus master, slow devsel, latency 32, IRQ 7, NUMA node 0
Memory at fe024000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [50] Power Management version 2
Kernel modules: snd_hda_intel
01:00.1 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] Cape Verde/Pitcairn
HDMI Audio [Radeon HD 7700/7800 Series]
Subsystem: PC Partner Limited / Sapphire Technology Device aab0
Flags: bus master, fast devsel, latency 0, IRQ 10, NUMA node 0
Memory at fd4fc000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [48] Vendor Specific Information: Len=08 <?>
Capabilities: [50] Power Management version 3
Capabilities: [58] Express Legacy Endpoint, MSI 00
Capabilities: [a0] MSI: Enable- Count=1/1 Maskable- 64bit+
Capabilities: [100] Vendor Specific Information: ID=0001 Rev=1 Len=010 <?>
Capabilities: [150] Advanced Error Reporting
Kernel modules: snd_hda_intel
02:00.0 Audio device: Creative Labs Sound Core3D [Sound Blaster Recon3D /
Z-Series] (rev 01)
Subsystem: Creative Labs SB1570 SB Audigy Fx
Flags: bus master, fast devsel, latency 0, IRQ 10, NUMA node 0
Memory at fd3fc000 (64-bit, non-prefetchable) [size=16K]
Memory at fd3f8000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [40] Power Management version 3
Capabilities: [50] MSI: Enable- Count=1/1 Maskable+ 64bit+
Capabilities: [70] Express Endpoint, MSI 00
Capabilities: [100] Advanced Error Reporting
Capabilities: [140] Virtual Channel
Capabilities: [170] Device Serial Number 00-00-00-00-00-00-00-00
Capabilities: [180] Power Budgeting <?>
Kernel modules: snd_hda_intel
Let me know what else to dump or try.
Thanks,
Vlastimil
2
5
[alsa-devel] [PATCH 1/2] ASoC: qcom: lpass-cpu: Remove unnecessary clock checks
by Bjorn Andersson 30 Jan '17
by Bjorn Andersson 30 Jan '17
30 Jan '17
Clean up the clock calling code by removing numerous IS_ERR() checks by
just assigning the clock NULL; as this turn all used functions in the
clk API to nops.
Also include the word "optional" in the error message when failing to acquire
the optional osr clocks.
Cc: Banajit Goswami <bgoswami(a)codeaurora.org>
Cc: Patrick Lai <plai(a)codeaurora.org>
Cc: Srinivas Kandagatla <srinivas.kandagatla(a)linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson(a)linaro.org>
---
sound/soc/qcom/lpass-cpu.c | 27 ++++++++++-----------------
1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index eff3f9a8b685..1b912a9bb791 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -33,9 +33,6 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
int ret;
- if (IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
- return 0;
-
ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
if (ret)
dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
@@ -50,23 +47,18 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
int ret;
- if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) {
- ret = clk_prepare_enable(
- drvdata->mi2s_osr_clk[dai->driver->id]);
- if (ret) {
- dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
- __func__, ret);
- return ret;
- }
+ ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->driver->id]);
+ if (ret) {
+ dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
+ __func__, ret);
+ return ret;
}
ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
if (ret) {
dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
__func__, ret);
- if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
- clk_disable_unprepare(
- drvdata->mi2s_osr_clk[dai->driver->id]);
+ clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
return ret;
}
@@ -80,8 +72,7 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
- if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
- clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
+ clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
}
static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
@@ -505,9 +496,11 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
clk_name);
if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
dev_warn(&pdev->dev,
- "%s() error getting mi2s-osr-clk: %ld\n",
+ "%s() error getting optional mi2s-osr-clk: %ld\n",
__func__,
PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
+
+ drvdata->mi2s_osr_clk[dai_id] = NULL;
}
if (variant->num_dai > 1)
--
2.11.0
1
1
30 Jan '17
On Mon, 30 Jan 2017 14:20:18 +0100,
Detlef Urban wrote:
>
> I bet on "global variables have been removed".
Good to hear, but I'm not sure. See below.
> But still unclear to me is if use of private
> data field in struct usb_mixer_elem_info is
> uncommon?
It's normal to use it.
> Add mixer quirk for Tascam US-16x08 usb interface.
> Even that this an usb compliant device,
> the input channels and DSP functions (EQ/Compressor)
> arn't accessible by default.
>
> Signed-off-by: Detlef Urban <onkel(a)paraair.de>
Well, the patch style looks still very incompatible.
Please run checkpatch.pl and fix the issues reported there at first.
Also, if it's your MUA that breaks the spacing of the patch, then
please fix your MUA setup, or use attachment as a last resort.
About the non-coding-style issues in the patch:
> +int snd_us16x08_recv_urb(struct snd_usb_audio *chip,
> + unsigned char *buf, int size)
Missing static?
> +int snd_us16x08_recv_urb_0xa1(struct snd_usb_audio *chip,
> + char *buffer, int size)
Ditto. I won't mention in all others. Please check each function
whether it really must be non-static or not.
> +{
> +
> + unsigned char buf[64] = {0,};
> + int err = snd_usb_ctl_msg(chip->dev,
> + usb_rcvctrlpipe(chip->dev, 0),
> + 2,
> + 0xa1, 0x0100, 0x100, buf, 14);
> + dev_err(&chip->dev->dev,
> + "us16x08: snd_us16x08_recv_urb: error: %d\n", err);
Is the intention to show always the error? If yes, please give some
more comments to the function itself.
> +
> + return 0;
> +}
> +
> +/* wrapper function to send prepared URB buffer to usb device. Return -1
> + * if something went wrong (FIXME: have to have more helpful error numbers)
Better to fix now :)
> + */
> +int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size)
....
> +struct meter_resp {
> + uint8_t a0;
> + uint8_t a1;
> + uint8_t a2;
> + uint8_t b0;
> + uint8_t b1;
> + uint8_t b2;
> + uint8_t c0;
> + uint8_t c1;
> + uint8_t c2;
> + uint8_t c3;
> +};
> +struct meter_resp *resp;
> +unsigned char meter_urb_buf[64] = {0,};
What about these are global...? I thought you bet it.
> +int snd_us16x08_eqswitch_info(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_info *uinfo)
> +{
> + uinfo->count = 1;
> + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
> + uinfo->value.integer.max = 1;
> + uinfo->value.integer.min = 0;
> + return 0;
> +}
Use the standard snd_ctl_boolean_mono_info().
> +static int snd_us16x08_eqswitch_put(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct usb_mixer_elem_info *elem = kcontrol->private_data;
> + struct snd_usb_audio *chip = elem->head.mixer->chip;
> + struct snd_us16x08_eq_all_store *store =
> + ((struct snd_us16x08_eq_all_store *) elem->private_data);
> + int index = ucontrol->id.index;
> +
> + char buf[sizeof(eqs_msq)];
> + int val, err = 0;
> +
> + val = ucontrol->value.integer.value[0];
> +
> + memcpy(buf, eqs_msq, sizeof(eqs_msq));
> +
> + store->low_store->valSwitch[index] = val;
> + store->midlow_store->valSwitch[index] = val;
> + store->midhigh_store->valSwitch[index] = val;
> + store->high_store->valSwitch[index] = val;
> +
> + buf[5] = index + 1;
> +
> + buf[20] = store->low_store->valSwitch[index];
> + buf[17] = store->low_store->valWidth[index];
> + buf[14] = store->low_store->valFreq[index];
> + buf[11] = store->low_store->valdB[index];
> + buf[8] = 0x01;
> + err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
> +
> + mdelay(15);
Need to be mdelay(), not msleep() or variant?
> +struct snd_us16x08_fader *snd_us16x08_create_mix_store(int default_val)
> +{
> + int i;
> + struct snd_us16x08_fader *tmp =
> + kmalloc(sizeof(struct snd_us16x08_fader), GFP_KERNEL);
Missing NULL check.
> +
> + for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++)
> + tmp->value[i] = default_val;
> + return tmp;
> +}
> +
> +struct snd_us16x08_comp_store *snd_us16x08_create_comp_store(void)
> +{
> + int i = 0;
> + struct snd_us16x08_comp_store *tmp =
> + kmalloc(sizeof(struct snd_us16x08_comp_store), GFP_KERNEL);
Ditto.
> +
> + for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
> + tmp->valThreshold[i] = 0x20; /* 0dB */
> + tmp->valRatio[i] = 0x00; /* 1:1 */
> + tmp->valGain[i] = 0x00; /* 0dB */
> + tmp->valSwitch[i] = 0x00; /* on */
> + tmp->valAttack[i] = 0x02; /* 2ms */
> + tmp->valRelease[i] = 0x01; /* 10ms */
> + }
> + return tmp;
> +}
> +
> +struct snd_us16x08_bypass_store *snd_us16x08_create_single_store(
> + int default_val)
> +{
> + struct snd_us16x08_bypass_store *tmp =
> + kmalloc(sizeof(struct snd_us16x08_bypass_store), GFP_KERNEL);
Ditto... For the whole!
> +void snd_us16x08_free_eq_store(struct snd_kcontrol *kctl)
> +{
> + snd_usb_mixer_elem_free(kctl);
> +}
> +
> +void snd_us16x08_free_mix_store(struct snd_kcontrol *kctl)
> +{
> + snd_usb_mixer_elem_free(kctl);
> +}
Why two different functions for the very same thing?
> +static int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + int i, set;
> + int val;
> + struct usb_mixer_elem_info *elem = kcontrol->private_data;
> + struct snd_usb_audio *chip = elem->head.mixer->chip;
> + struct snd_us16x08_meter_store *store = elem->private_data;
> + /* struct snd_us16x08_comp_store *comp_store; */
> +
> + if (elem) {
> + store = (struct snd_us16x08_meter_store *) elem->private_data;
> + chip = elem->head.mixer->chip;
> + }
> +
> + switch (kcontrol->private_value) {
> + case 0:
> + snd_us16x08_send_urb(chip, mix_init_msg1, 4);
> + snd_us16x08_recv_urb(chip, meter_urb_buf,
> + sizeof(meter_urb_buf));
> + kcontrol->private_value++;
> + break;
> + case 1:
> + snd_us16x08_recv_urb(chip, meter_urb_buf,
> + sizeof(meter_urb_buf));
> + kcontrol->private_value++;
> + break;
> + case 2:
> + snd_us16x08_recv_urb(chip, meter_urb_buf,
> + sizeof(meter_urb_buf));
> + kcontrol->private_value++;
> + break;
> + case 3:
> + mix_init_msg2[2] = snd_get_meter_comp_index(store);
> + snd_us16x08_send_urb(chip, mix_init_msg2, 10);
> + snd_us16x08_recv_urb(chip, meter_urb_buf,
> + sizeof(meter_urb_buf));
> + kcontrol->private_value = 0;
> + break;
> + }
.....
WTF does this function do...? Please add more comments.
> +int snd_us16x08_controls_create_eq(struct usb_mixer_interface *mixer)
> +{
> +
> + int err;
> + char name[64];
> + struct usb_mixer_elem_info *elem;
> +
> + struct snd_us16x08_eq_store *eq_low_store =
> + snd_us16x08_create_eq_store(0x01);
> + struct snd_us16x08_eq_store *eq_midlow_store =
> + snd_us16x08_create_eq_store(0x02);
> + struct snd_us16x08_eq_store *eq_midhigh_store =
> + snd_us16x08_create_eq_store(0x03);
> + struct snd_us16x08_eq_store *eq_high_store =
> + snd_us16x08_create_eq_store(0x04);
> + struct snd_us16x08_eq_all_store *eq_all_store =
> + kmalloc(sizeof(struct snd_us16x08_eq_all_store), GFP_KERNEL);
> +
> + eq_all_store->low_store = eq_low_store;
> + eq_all_store->midlow_store = eq_midlow_store;
> + eq_all_store->midhigh_store = eq_midhigh_store;
> + eq_all_store->high_store = eq_high_store;
You didn't check NULL at all here...
> + snprintf(name, sizeof(name), "5 Low");
> + err = add_new_ctl(mixer, &snd_us16x08_eqlevel_ctl,
> + SND_US16X08_ID_EQLOWLEVEL, 0x00, 0, USB_MIXER_U8, 1, name,
> + (void *) eq_low_store, snd_us16x08_free_eq_store, &elem);
> + if (err < 0)
> + return err;
> +
> + snprintf(name, sizeof(name), "51 LowFreq");
....
Please use a table for this kind of code.
> +int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
> +{
> +
> + int err;
> + char name[64];
> + struct usb_mixer_elem_info *elem;
> + struct snd_us16x08_fader *route_store;
> + struct snd_us16x08_comp_store *comp_store;
> + struct snd_us16x08_meter_store *meter_store;
> +
> + if (mixer->chip->num_interfaces > 0) {
What is this?
> + route_store = snd_us16x08_create_mix_store(0);
Missing error check.
> + route_store->value[0] = 0;
> + route_store->value[1] = 1;
> + route_store->value[2] = 4;
> + route_store->value[3] = 5;
> + route_store->value[4] = 6;
> + route_store->value[5] = 7;
> + route_store->value[6] = 8;
> + route_store->value[7] = 9;
> + snprintf(name, sizeof(name), "Route");
> + err = add_new_ctl(mixer, &snd_us16x08_route_ctl,
> + 0x00, 0x00, 0,
> + USB_MIXER_U8, 1, name, (void *) route_store,
> + snd_us16x08_free_mix_store, &elem);
> + if (err < 0)
> + return err;
> +
> + snprintf(name, sizeof(name), "Master");
.....
Please use a table.
> --- /dev/null
> +++ b/sound/usb/mixer_us16x08.h
> @@ -0,0 +1,132 @@
> +#ifndef __USB_MIXER_US16X08_H
> +#define __USB_MIXER_US16X08_H
> +
> +
> +#define SND_US16X08_MIN_CHANNELS 0
Zero channel is allowed...?
> +#define SND_US16X08_MAX_CHANNELS 16
> +
> +/* set macro for kcontrol private_value */
> +#define SND_US16X08_KCSET(bias, step, min, max) \
> + ((bias << 24) | (step << 16) | (min << 8) | max)
Put parentheses to each argument in a macro.
> +struct snd_us16x08_fader {
> + uint8_t value[SND_US16X08_MAX_CHANNELS];
Use u8 for the kernel code.
> +struct snd_us16x08_comp_store {
> + int8_t valThreshold[SND_US16X08_MAX_CHANNELS];
> + uint8_t valAttack[SND_US16X08_MAX_CHANNELS];
> + uint8_t valRelease[SND_US16X08_MAX_CHANNELS];
> + uint8_t valRatio[SND_US16X08_MAX_CHANNELS];
> + uint8_t valGain[SND_US16X08_MAX_CHANNELS];
> + uint8_t valSwitch[SND_US16X08_MAX_CHANNELS];
> +};
> +
> +struct snd_us16x08_meter_store {
> + long meter_level[SND_US16X08_MAX_CHANNELS];
> + long master_level[2]; /* level of meter for master output */
The size of long depends on the architecture. Do you want 32bit or
64bit integer? For the latter, use s64 or u64. For the former, just
use the standard int.
> + int comp_index;
> + int comp_active_index;
> + long comp_level[16]; /* compressor reduction level of current
> channel */
Ditto.
> + struct snd_us16x08_comp_store *comp_store;
> +};
> +
> +struct snd_us16x08_bypass_store {
> + int value;
> +};
What's the merit of this struct?
> +typedef void(*opt_free)(struct snd_kcontrol *kctl);
Don't use typedef unless really required.
> +int snd_us16x08_mix_info(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_info *uinfo);
> +
> +int snd_us16x08_controls_create(struct usb_mixer_interface *mixer);
> +
> +int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size);
> +
> +int snd_us16x08_cur_channel(void);
> +
> +int add_new_ctl(struct usb_mixer_interface *mixer,
> + const struct snd_kcontrol_new *ncontrol,
> + int index, int offset, int num, int val_type, int channels,
> + const char *name, const void *opt,
> + opt_free freeer, struct usb_mixer_elem_info **elem_ret);
> +
> +int snd_us16x08_controls_create_eq(struct usb_mixer_interface *mixer);
> +int snd_us16x08_controls_create_comp(struct usb_mixer_interface *mixer);
> +
> +struct snd_us16x08_comp_store *get_comp_store(void);
Where is it defined?
Also, did you test suspend/resume? Your code seems missing the
restore mixer callback. Without the proper restore callback, S3 may
work, but S4 won't.
thanks,
Takashi
1
0
[alsa-devel] [PATCH] Sound: soc: samsung - Fix possible NULL derefrence.
by Shailendra Verma 30 Jan '17
by Shailendra Verma 30 Jan '17
30 Jan '17
of_device_get_match_data could return NULL, and so can cause
a NULL pointer dereference later.
Signed-off-by: Shailendra Verma <shailendra.v(a)samsung.com>
---
sound/soc/samsung/i2s.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 7825bff..b5acce2 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -1224,8 +1224,13 @@ static int samsung_i2s_probe(struct platform_device *pdev)
const struct samsung_i2s_dai_data *i2s_dai_data;
int ret;
- if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
+ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
i2s_dai_data = of_device_get_match_data(&pdev->dev);
+ if (!i2s_dai_data) {
+ dev_err(&pdev->dev, "no device match found\n");
+ return -ENODEV;
+ }
+ }
else
i2s_dai_data = (struct samsung_i2s_dai_data *)
platform_get_device_id(pdev)->driver_data;
--
1.7.9.5
2
1
30 Jan '17
Add mixer quirk for Tascam US-16x08 usb interface.
Even that this an usb compliant device,
the input channels and DSP functions (EQ/Compressor)
arn't accessible by default.
Signed-off by: Detlef Urban <onkel(a)paraair.de>
---
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 2d2d122..5394264 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -10,6 +10,9 @@ snd-usb-audio-objs := card.o \
mixer.o \
mixer_quirks.o \
mixer_scarlett.o \
+ mixer_us16x08.o \
+ mixer_us16x08_eq.o \
+ mixer_us16x08_comp.o \
pcm.o \
proc.o \
quirks.o \
@@ -25,4 +28,3 @@ obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/
-obj-$(CONFIG_SND_USB_LINE6) += line6/
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 04991b0..4fa0053 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -43,6 +43,7 @@
#include "mixer.h"
#include "mixer_quirks.h"
#include "mixer_scarlett.h"
+#include "mixer_us16x08.h"
#include "helper.h"
extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
@@ -1729,6 +1730,10 @@ int snd_usb_mixer_apply_create_quirk(struct
usb_mixer_interface *mixer)
return err;
switch (mixer->chip->usb_id) {
+ /* Tascam US-16x08 */
+ case USB_ID(0x0644, 0x8047):
+ err = snd_us16x08_controls_create(mixer);
+ break;
case USB_ID(0x041e, 0x3020):
case USB_ID(0x041e, 0x3040):
case USB_ID(0x041e, 0x3042):
diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c
new file mode 100644
index 0000000..177ec5f
--- /dev/null
+++ b/sound/usb/mixer_us16x08.c
@@ -0,0 +1,815 @@
+/*
+ * Tascam US-16x08 ALSA driver
+ *
+ * Copyright (c) 2016 by Detlef Urban (onkel(a)paraair.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/audio-v2.h>
+#include "linux/kthread.h"
+
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "usbaudio.h"
+#include "mixer.h"
+#include "helper.h"
+
+#include "mixer_us16x08.h"
+
+#define FADER_INFOPUTGET_NOLOG
+
+static char route_msg[] = {
+ 0x61,
+ 0x02,
+ 0x03, /* input from master (0x02) or input from computer bus (0x03) */
+ 0x62,
+ 0x02,
+ 0x01, /* input index (0x01/0x02 eq. left/right) or bus (0x01-0x08) */
+ 0x41,
+ 0x01,
+ 0x61,
+ 0x02,
+ 0x01,
+ 0x62,
+ 0x02,
+ 0x01, /* output index (0x01-0x08) */
+ 0x42,
+ 0x01,
+ 0x43,
+ 0x01,
+ 0x00,
+ 0x00
+};
+
+static char mix_init_msg1[] = {
+ 0x71, 0x01, 0x00, 0x00
+};
+static char mix_init_msg2[] = {
+ 0x62, 0x02, 0x00, 0x61, 0x02, 0x04, 0xb1, 0x01, 0x00, 0x00
+};
+
+static int comp_channel = 1;
+
+static char mix_msg_in[] = {
+ CTLMSGHEAD_IN, /* the default message head */
+ 0x81, /* 0x06: Controller ID */
+ 0x02, /* 0x07: */
+ 0x00, /* 0x08: Value of common mixer */
+ 0x00,
+ 0x00
+};
+static char mix_msg_out[] = {
+ CTLMSGHEAD_OUT, /* the default message head */
+ 0x81, /* 0x06: Controller ID */
+ 0x02, /* 0x07: */
+ 0x00, /* 0x08: Value of common mixer */
+ 0x00,
+ 0x00
+};
+
+static char bypass_msg_out[] = {
+ 0x45,
+ 0x02,
+ 0x01, // on/off flag
+ 0x00,
+ 0x00
+};
+
+static char bus_msg_out[] = {
+ 0x44,
+ 0x02,
+ 0x01, // on/off flag
+ 0x00,
+ 0x00
+};
+
+int snd_us16x08_recv_urb(struct snd_usb_audio *chip,
+ unsigned char *buf, int size)
+{
+
+ mutex_lock(&chip->mutex);
+ snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0),
+ SND_US16X08_URB_METER_REQUEST,
+ SND_US16X08_URB_METER_REQUESTTYPE, 0, 0, buf, size);
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+int snd_us16x08_recv_urb_0xa1(struct snd_usb_audio *chip,
+ char *buffer, int size)
+{
+
+ unsigned char buf[64] = {0,};
+ int err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0),
+ 2,
+ 0xa1, 0x0100, 0x100, buf, 14);
+ dev_err(&chip->dev->dev,
+ "us16x08: snd_us16x08_recv_urb: error: %d\n", err);
+
+ return 0;
+}
+
+/* wrapper function to send prepared URB buffer to usb device. Return -1
+ * if something went wrong (FIXME: have to have more helpful error
numbers) */
+int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size)
+{
+ int count = -1;
+
+ if (chip) {
+ count = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0),
+ SND_US16X08_URB_REQUEST,
+ SND_US16X08_URB_REQUESTTYPE,
+ 0, 0, buf, size);
+ }
+
+ return(count == size) ? 0 : -1;
+}
+
+struct meter_resp {
+ uint8_t a0;
+ uint8_t a1;
+ uint8_t a2;
+ uint8_t b0;
+ uint8_t b1;
+ uint8_t b2;
+ uint8_t c0;
+ uint8_t c1;
+ uint8_t c2;
+ uint8_t c3;
+};
+struct meter_resp *resp = NULL;
+unsigned char meter_urb_buf[64] = {0,};
+
+int snd_us16x08_route_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->count = 1;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
+ uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
+ uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
+ return 0;
+}
+
+static int snd_us16x08_route_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_us16x08_fader *store =
+ (struct snd_us16x08_fader *) elem->private_data;
+ int index = ucontrol->id.index;
+
+ /* we have only eight output channels, so ignore all others */
+ ucontrol->value.integer.value[0] = store->value[index];
+
+ return 0;
+}
+
+static int snd_us16x08_route_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_fader *store =
+ (struct snd_us16x08_fader *) elem->private_data;
+ int index = ucontrol->id.index;
+ char buf[sizeof(route_msg)];
+ int val, val_org, err = 0;
+
+ /* prepare the message buffer from static one */
+ memcpy(buf, route_msg, sizeof(route_msg));
+
+ /* get the new value */
+ val = ucontrol->value.integer.value[0];
+ if (val < 2) { /* input comes from a master channel */
+ val_org = val;
+ buf[2] = 0x02;
+ } else { /* input comes from a computer channel */
+ buf[2] = 0x03;
+ val_org = val - 2;
+ }
+
+ buf[5] = (unsigned char) (val_org & 0x0f) + 1;
+ buf[13] = index + 1;
+
+ err = snd_us16x08_send_urb(chip, buf, sizeof(route_msg));
+
+ if (err == 0)
+ store->value[index] = val;
+
+ return err == 0 ? 1 : 0;
+}
+
+static int snd_us16x08_master_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_us16x08_fader *store =
+ (struct snd_us16x08_fader *) elem->private_data;
+ int index = ucontrol->id.index;
+
+ ucontrol->value.integer.value[0] = store->value[index];
+
+ return 0;
+}
+
+int snd_us16x08_master_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->count = 1;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
+ uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
+ uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
+ return 0;
+}
+
+static int snd_us16x08_master_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_fader *store =
+ (struct snd_us16x08_fader *) elem->private_data;
+ char buf[sizeof(mix_msg_out)];
+ int val, err = 0;
+ int index = ucontrol->id.index;
+
+
+ /* prepare the message buffer from static one */
+ memcpy(buf, mix_msg_out, sizeof(mix_msg_out));
+
+ val = ucontrol->value.integer.value[0];
+ dev_dbg(&chip->dev->dev,
+ "snd_us16x08_master_put index:%d, val, %d", index, val);
+
+ buf[8] = val - SND_US16X08_KCBIAS(kcontrol);
+ buf[6] = elem->head.id;
+
+ buf[5] = index + 1;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out));
+
+ if (err == 0)
+ store->value[index] = val;
+
+ return err == 0 ? 1 : 0;
+}
+
+static int snd_us16x08_bypass_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_us16x08_bypass_store *store =
+ (struct snd_us16x08_bypass_store *) elem->private_data;
+
+ ucontrol->value.integer.value[0] = store->value;
+
+ return 0;
+}
+
+static int snd_us16x08_bypass_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_bypass_store *store =
+ (struct snd_us16x08_bypass_store *) elem->private_data;
+
+ // prepare message buffer
+ char buf[sizeof(bypass_msg_out)];
+ int val, err = 0;
+
+ /* prepare the message buffer from static one */
+ memcpy(buf, bypass_msg_out, sizeof(bypass_msg_out));
+
+ val = ucontrol->value.integer.value[0];
+ dev_dbg(&chip->dev->dev, "snd_us16x08_bypass_put val: %d", val);
+
+ buf[2] = val;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(bypass_msg_out));
+
+ if (err == 0)
+ store->value = val;
+
+ return err == 0 ? 1 : 0;
+}
+
+static int snd_us16x08_bussout_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_bypass_store *store =
+ (struct snd_us16x08_bypass_store *) elem->private_data;
+
+ // prepare message buffer
+ char buf[sizeof(bus_msg_out)];
+ int val, err = 0;
+
+ /* prepare the message buffer from static one */
+ memcpy(buf, bus_msg_out, sizeof(bus_msg_out));
+
+ val = ucontrol->value.integer.value[0];
+ dev_dbg(&chip->dev->dev, "snd_us16x08_bus_out_put val: %d", val);
+
+ buf[2] = val;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(bus_msg_out));
+
+ if (err == 0)
+ store->value = val;
+
+ return err == 0 ? 1 : 0;
+}
+
+/*
+gets a current mixer value from common store
+ */
+static int snd_us16x08_mix_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_us16x08_fader *store =
+ (struct snd_us16x08_fader *) elem->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ int index = ucontrol->id.index;
+
+ ucontrol->value.integer.value[0] = store->value[index];
+ dev_dbg(&chip->dev->dev,
+ "snd_us16x08_mix_get: index:%d, val:%d\n",
+ index, store->value[index]);
+
+ return 0;
+}
+
+static int snd_us16x08_mix_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_fader *store =
+ (struct snd_us16x08_fader *) elem->private_data;
+ char buf[sizeof(mix_msg_in)];
+ int val, err;
+ int index = ucontrol->id.index;
+
+
+ memcpy(buf, mix_msg_in, sizeof(mix_msg_in));
+
+ val = ucontrol->value.integer.value[0];
+
+ buf[8] = val - SND_US16X08_KCBIAS(kcontrol);
+ buf[6] = elem->head.id;
+ buf[5] = index + 1;
+
+ err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_in));
+
+ if (err == 0)
+ store->value[index] = val;
+
+ return err == 0 ? 1 : 0;
+}
+
+int snd_us16x08_mix_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->count = 1;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
+ uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
+ uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
+ return 0;
+}
+
+static int snd_us16x08_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+
+ uinfo->count = 1;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->value.integer.max = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+
+static struct snd_kcontrol_new snd_us16x08_mix_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_mix_get,
+ .put = snd_us16x08_mix_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133),
+};
+static struct snd_kcontrol_new snd_us16x08_pan_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_mix_get,
+ .put = snd_us16x08_mix_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 254),
+};
+static struct snd_kcontrol_new snd_us16x08_mute_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_switch_info,
+ .get = snd_us16x08_mix_get,
+ .put = snd_us16x08_mix_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1),
+};
+static struct snd_kcontrol_new snd_us16x08_phase_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_switch_info,
+ .get = snd_us16x08_mix_get,
+ .put = snd_us16x08_mix_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1),
+};
+static struct snd_kcontrol_new snd_us16x08_master_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 2,
+ .info = snd_us16x08_master_info,
+ .get = snd_us16x08_master_get,
+ .put = snd_us16x08_master_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133),
+};
+static struct snd_kcontrol_new snd_us16x08_route_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 8,
+ .info = snd_us16x08_route_info,
+ .get = snd_us16x08_route_get,
+ .put = snd_us16x08_route_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 9),
+};
+static struct snd_kcontrol_new snd_us16x08_bypass_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 1,
+ .info = snd_us16x08_switch_info,
+ .get = snd_us16x08_bypass_get,
+ .put = snd_us16x08_bypass_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1),
+};
+static struct snd_kcontrol_new snd_us16x08_bussout_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 1,
+ .info = snd_us16x08_switch_info,
+ .get = snd_us16x08_bypass_get,
+ .put = snd_us16x08_bussout_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1),
+};
+
+static struct snd_kcontrol_new snd_us16x08_master_mute_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 1,
+ .info = snd_us16x08_switch_info,
+ .get = snd_us16x08_master_get,
+ .put = snd_us16x08_master_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1),
+};
+
+struct snd_us16x08_fader *snd_us16x08_create_mix_store(int default_val)
+{
+ int i;
+ struct snd_us16x08_fader *tmp =
+ kmalloc(sizeof(struct snd_us16x08_fader), GFP_KERNEL);
+
+ for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++)
+ tmp->value[i] = default_val;
+ return tmp;
+}
+
+struct snd_us16x08_bypass_store *snd_us16x08_create_single_store(
+ int default_val)
+{
+ struct snd_us16x08_bypass_store *tmp =
+ kmalloc(sizeof(struct snd_us16x08_bypass_store), GFP_KERNEL);
+
+ tmp->value = default_val;
+ return tmp;
+}
+
+void snd_us16x08_free_mix_store(struct snd_kcontrol *kctl)
+{
+ snd_usb_mixer_elem_free(kctl);
+}
+
+/*
+meter level transports
+ */
+static int snd_us16x08_meter_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->count = 1;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.max = 0x7FFF;
+ uinfo->value.integer.min = 0;
+
+ return 0;
+}
+
+static int snd_us16x08_meter_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return 1;
+}
+
+static int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i, set;
+ int val;
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_meter_store *store = elem->private_data;
+ struct snd_us16x08_comp_store* comp_store;
+
+ if (elem) {
+ store = (struct snd_us16x08_meter_store *) elem->private_data;
+ chip = elem->head.mixer->chip;
+ }
+
+ switch (kcontrol->private_value) {
+ case 0:
+ snd_us16x08_send_urb(chip, mix_init_msg1, 4);
+ snd_us16x08_recv_urb(chip, meter_urb_buf,
+ sizeof(meter_urb_buf));
+ kcontrol->private_value++;
+ break;
+ case 1:
+ snd_us16x08_recv_urb(chip, meter_urb_buf,
+ sizeof(meter_urb_buf));
+ kcontrol->private_value++;
+ break;
+ case 2:
+ snd_us16x08_recv_urb(chip, meter_urb_buf,
+ sizeof(meter_urb_buf));
+ kcontrol->private_value++;
+ break;
+ case 3:
+ mix_init_msg2[2] = comp_channel++;
+ snd_us16x08_send_urb(chip, mix_init_msg2, 10);
+ snd_us16x08_recv_urb(chip, meter_urb_buf,
+ sizeof(meter_urb_buf));
+ kcontrol->private_value = 0;
+
+ comp_store = get_comp_store();
+ if (comp_channel == 17)
+ comp_channel = 1;
+ while (!comp_store->valSwitch[comp_channel - 1] &&
+ comp_channel < 17)
+ comp_channel++;
+ if (comp_channel == 17)
+ comp_channel = 1;
+ break;
+
+ }
+
+ for (set = 0; set < 6; set++) {
+ resp = (struct meter_resp *) &(meter_urb_buf[4 + set * 10]);
+ val = resp->c2 + (resp->c3 << 8);
+ if (resp->a0 == 0x61 && resp->a1 == 0x02 &&
+ resp->a2 == 0x04 && resp->b0 == 0x62) {
+ if (resp->c0 == 0x72)
+ if (store)
+ store->meter_level[resp->b2 - 1] = val;
+ if (resp->c0 == 0xb2) {
+ if (store)
+ store->comp_level[resp->b2 - 1] = val;
+ }
+ }
+ if (resp->a0 == 0x61 && resp->a1 == 0x02 &&
+ resp->a2 == 0x02 && resp->b0 == 0x62) {
+ if (store)
+ store->master_level[resp->b2 - 1] = val;
+ }
+ }
+
+ for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
+ ucontrol->value.integer.value[i] =
+ store ? store->meter_level[i] : 0;
+ }
+
+ ucontrol->value.integer.value[i++] = store ? store->master_level[0]
: 0;
+ ucontrol->value.integer.value[i++] = store ? store->master_level[1]
: 0;
+
+ for (i = 2; i < SND_US16X08_MAX_CHANNELS + 2; i++)
+ ucontrol->value.integer.value[i + SND_US16X08_MAX_CHANNELS] =
+ store ? store->comp_level[i] : 0;
+
+ return 1;
+}
+static struct snd_kcontrol_new snd_us16x08_meter_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .info = snd_us16x08_meter_info,
+ .get = snd_us16x08_meter_get,
+ .put = snd_us16x08_meter_put,
+};
+
+struct snd_us16x08_meter_store *snd_us16x08_create_meter_store(void)
+{
+ struct snd_us16x08_meter_store *tmp =
+ kzalloc(sizeof(struct snd_us16x08_meter_store), GFP_KERNEL);
+
+ if (!tmp)
+ return NULL;
+ return tmp;
+
+}
+
+void snd_us16x08_free_meter_store(struct snd_kcontrol *kctl)
+{
+ kfree(kctl->private_data);
+}
+
+int add_new_ctl(struct usb_mixer_interface *mixer,
+ const struct snd_kcontrol_new *ncontrol,
+ int index, int offset, int num, int val_type,
+ int channels, const char *name, const struct snd_us16x08_fader *opt,
+ opt_free freeer, struct usb_mixer_elem_info **elem_ret)
+{
+ struct snd_kcontrol *kctl;
+ struct usb_mixer_elem_info *elem;
+ int err;
+
+ usb_audio_dbg(mixer->chip, "us16x08 add mixer %s\n", name);
+
+ elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+ if (!elem)
+ return -ENOMEM;
+
+ elem->head.mixer = mixer;
+ elem->control = offset;
+ elem->idx_off = num;
+ elem->head.id = index;
+ elem->val_type = val_type;
+ elem->channels = channels;
+ elem->private_data = (void *) opt;
+
+ kctl = snd_ctl_new1(ncontrol, elem);
+ if (!kctl) {
+ kfree(elem);
+ return -ENOMEM;
+ }
+
+ kctl->private_free = freeer;
+
+ strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+
+ err = snd_usb_mixer_add_control(&elem->head, kctl);
+ if (err < 0)
+ return err;
+
+ if (elem_ret)
+ *elem_ret = elem;
+
+ return 0;
+}
+
+int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
+{
+
+ int err;
+ char name[64];
+ struct usb_mixer_elem_info *elem;
+
+
+ if (mixer->chip->num_interfaces > 0) {
+ struct snd_us16x08_fader *route_store =
+ snd_us16x08_create_mix_store(0);
+
+ route_store->value[0] = 0;
+ route_store->value[1] = 1;
+ route_store->value[2] = 4;
+ route_store->value[3] = 5;
+ route_store->value[4] = 6;
+ route_store->value[5] = 7;
+ route_store->value[6] = 8;
+ route_store->value[7] = 9;
+ snprintf(name, sizeof(name), "Route");
+ err = add_new_ctl(mixer, &snd_us16x08_route_ctl,
+ 0x00, 0x00, 0,
+ USB_MIXER_U8, 1, name, (void *) route_store,
+ snd_us16x08_free_mix_store, &elem);
+ if (err < 0)
+ return err;
+
+
+ snprintf(name, sizeof(name), "Master");
+ err = add_new_ctl(mixer, &snd_us16x08_master_ctl,
+ SND_US16X08_ID_FADER, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) snd_us16x08_create_mix_store(0),
+ snd_us16x08_free_mix_store, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "Bypass");
+ err = add_new_ctl(mixer, &snd_us16x08_bypass_ctl,
+ SND_US16X08_ID_BYPASS, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) snd_us16x08_create_single_store(0),
+ snd_us16x08_free_mix_store, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "Buss out");
+ err = add_new_ctl(mixer, &snd_us16x08_bussout_ctl,
+ SND_US16X08_ID_BUSS_OUT, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) snd_us16x08_create_single_store(0),
+ snd_us16x08_free_mix_store, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "Master Mute");
+ err = add_new_ctl(mixer, &snd_us16x08_master_mute_ctl,
+ SND_US16X08_ID_MUTE, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) snd_us16x08_create_single_store(0),
+ snd_us16x08_free_mix_store, &elem);
+ if (err < 0)
+ return err;
+
+
+ snprintf(name, sizeof(name), "Phase");
+ err = add_new_ctl(mixer, &snd_us16x08_phase_ctl,
+ SND_US16X08_ID_PHASE, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) snd_us16x08_create_mix_store(0),
+ snd_us16x08_free_mix_store, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "Fader");
+ err = add_new_ctl(mixer, &snd_us16x08_mix_ctl,
+ SND_US16X08_ID_FADER, 0x00, 0, USB_MIXER_S16, 1, name,
+ (void *) snd_us16x08_create_mix_store(127),
+ snd_us16x08_free_mix_store, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "3 Mute");
+ err = add_new_ctl(mixer, &snd_us16x08_mute_ctl,
+ SND_US16X08_ID_MUTE, 0x00, 0, USB_MIXER_BOOLEAN, 1,
+ name, (void *) snd_us16x08_create_mix_store(0),
+ snd_us16x08_free_mix_store, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "4 Pan");
+ err = add_new_ctl(mixer, &snd_us16x08_pan_ctl,
+ SND_US16X08_ID_PAN, 0x00, 0, USB_MIXER_U16, 1, name,
+ (void *) snd_us16x08_create_mix_store(127),
+ snd_us16x08_free_mix_store, &elem);
+ if (err < 0)
+ return err;
+
+ resp = kmalloc(sizeof(struct meter_resp), GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ snprintf(name, sizeof(name), "Z Meter");
+ err = add_new_ctl(mixer, &snd_us16x08_meter_ctl,
+ SND_US16X08_ID_METER, 0x00, 0, USB_MIXER_U16, 1, name,
+ (void *) snd_us16x08_create_meter_store(),
+ snd_us16x08_free_meter_store, &elem);
+ if (err < 0)
+ return err;
+
+ err = snd_us16x08_controls_create_eq(mixer);
+ if (err < 0)
+ return err;
+
+ err = snd_us16x08_controls_create_comp(mixer);
+ if (err < 0)
+ return err;
+
+
+ } else {
+ usb_audio_dbg(mixer->chip,
+ "mixer->chip->num_interfaces == 0\n");
+ }
+
+ return 0;
+}
diff --git a/sound/usb/mixer_us16x08.h b/sound/usb/mixer_us16x08.h
new file mode 100644
index 0000000..6423547
--- /dev/null
+++ b/sound/usb/mixer_us16x08.h
@@ -0,0 +1,136 @@
+#ifndef __USB_MIXER_US16X08_H
+#define __USB_MIXER_US16X08_H
+
+
+#define SND_US16X08_MIN_CHANNELS 0
+#define SND_US16X08_MAX_CHANNELS 16
+
+/* define some bias, cause some alsa-mixers wont work with
+ * negative ranges or if mixer-min != 0 */
+#define SND_US16X08_NO_BIAS 0
+#define SND_US16X08_FADER_BIAS 127
+#define SND_US16X08_EQ_HIGHFREQ_BIAS 0x20
+#define SND_US16X08_COMP_THRESHOLD_BIAS 0x20
+#define SND_US16X08_COMP_ATTACK_BIAS 2
+#define SND_US16X08_COMP_RELEASE_BIAS 1
+
+/* get macro for components of kcontrol private_value */
+#define SND_US16X08_KCBIAS(x) ((x->private_value >> 24) & 0xff)
+#define SND_US16X08_KCSTEP(x) ((x->private_value >> 16) & 0xff)
+#define SND_US16X08_KCMIN(x) ((x->private_value >> 8) & 0xff)
+#define SND_US16X08_KCMAX(x) ((x->private_value >> 0) & 0xff)
+/* set macro for kcontrol private_value */
+#define SND_US16X08_KCSET(bias, step, min, max) \
+ ((bias << 24) | (step << 16) | (min << 8) | max)
+
+/* the URB request/type to control Tascam mixers */
+#define SND_US16X08_URB_REQUEST 0x1D
+#define SND_US16X08_URB_REQUESTTYPE 0x40
+
+/* the URB params to retrieve meter ranges */
+#define SND_US16X08_URB_METER_REQUEST 0x1e
+#define SND_US16X08_URB_METER_REQUESTTYPE 0xc0
+
+/* Common Channel control IDs */
+#define SND_US16X08_ID_BYPASS 0x45
+#define SND_US16X08_ID_BUSS_OUT 0x44
+#define SND_US16X08_ID_PHASE 0x85
+#define SND_US16X08_ID_MUTE 0x83
+#define SND_US16X08_ID_FADER 0x81
+#define SND_US16X08_ID_PAN 0x82
+#define SND_US16X08_ID_METER 0xB1
+
+/* EQ level IDs */
+#define SND_US16X08_ID_EQLOWLEVEL 0x01
+#define SND_US16X08_ID_EQLOWMIDLEVEL 0x02
+#define SND_US16X08_ID_EQHIGHMIDLEVEL 0x03
+#define SND_US16X08_ID_EQHIGHLEVEL 0x04
+
+/* EQ frequence IDs */
+#define SND_US16X08_ID_EQLOWFREQ 0x11
+#define SND_US16X08_ID_EQLOWMIDFREQ 0x12
+#define SND_US16X08_ID_EQHIGHMIDFREQ 0x13
+#define SND_US16X08_ID_EQHIGHFREQ 0x14
+
+/* EQ width IDs */
+#define SND_US16X08_ID_EQLOWMIDWIDTH 0x22
+#define SND_US16X08_ID_EQHIGHMIDWIDTH 0x23
+
+#define SND_US16X08_ID_EQENABLE 0x31
+
+/* Compressor Ids */
+#define SND_US16X08_ID_COMP_THRESHOLD 0x01
+#define SND_US16X08_ID_COMP_RATIO 0x02
+#define SND_US16X08_ID_COMP_ATTACK 0x03
+#define SND_US16X08_ID_COMP_RELEASE 0x04
+#define SND_US16X08_ID_COMP_GAIN 0x05
+#define SND_US16X08_ID_COMP_SWITCH 0x06
+
+struct snd_us16x08_fader {
+ uint8_t value[SND_US16X08_MAX_CHANNELS];
+};
+
+struct snd_us16x08_eq_store {
+ uint8_t valdB[SND_US16X08_MAX_CHANNELS];
+ uint8_t valFreq[SND_US16X08_MAX_CHANNELS];
+ uint8_t valWidth[SND_US16X08_MAX_CHANNELS];
+ uint8_t valSwitch[SND_US16X08_MAX_CHANNELS];
+};
+
+struct snd_us16x08_eq_all_store {
+ struct snd_us16x08_eq_store *low_store;
+ struct snd_us16x08_eq_store *midlow_store;
+ struct snd_us16x08_eq_store *midhigh_store;
+ struct snd_us16x08_eq_store *high_store;
+};
+
+struct snd_us16x08_comp_store {
+ int8_t valThreshold[SND_US16X08_MAX_CHANNELS];
+ uint8_t valAttack[SND_US16X08_MAX_CHANNELS];
+ uint8_t valRelease[SND_US16X08_MAX_CHANNELS];
+ uint8_t valRatio[SND_US16X08_MAX_CHANNELS];
+ uint8_t valGain[SND_US16X08_MAX_CHANNELS];
+ uint8_t valSwitch[SND_US16X08_MAX_CHANNELS];
+};
+
+struct snd_us16x08_meter_store {
+ long meter_level[SND_US16X08_MAX_CHANNELS];
+ long master_level[2]; /* level of meter for master output */
+ long comp_level[16]; /* compressor reduction level of current
channel */
+};
+
+struct snd_us16x08_bypass_store {
+ int value;
+};
+
+typedef void(*opt_free)(struct snd_kcontrol *kctl);
+
+
+/* |- Channel index (5) */
+/* | */
+/* v */
+#define CTLMSGHEAD_IN 0x61, 0x02, 0x04, 0x62, 0x02, 0x01
+#define CTLMSGHEAD_OUT 0x61, 0x02, 0x02, 0x62, 0x02, 0x01
+
+int snd_us16x08_mix_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+
+int snd_us16x08_controls_create(struct usb_mixer_interface *mixer);
+
+int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size);
+
+int snd_us16x08_cur_channel(void);
+
+int add_new_ctl(struct usb_mixer_interface *mixer,
+ const struct snd_kcontrol_new *ncontrol,
+ int index, int offset, int num, int val_type, int channels,
+ const char *name, const struct snd_us16x08_fader *opt,
+ opt_free freeer, struct usb_mixer_elem_info **elem_ret);
+
+int snd_us16x08_controls_create_eq(struct usb_mixer_interface *mixer);
+int snd_us16x08_controls_create_comp(struct usb_mixer_interface *mixer);
+
+struct snd_us16x08_comp_store *get_comp_store(void);
+
+#endif /* __USB_MIXER_US16X08_H */
+
diff --git a/sound/usb/mixer_us16x08_comp.c b/sound/usb/mixer_us16x08_comp.c
new file mode 100644
index 0000000..2bc0146
--- /dev/null
+++ b/sound/usb/mixer_us16x08_comp.c
@@ -0,0 +1,316 @@
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/audio-v2.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+
+#include "usbaudio.h"
+#include "mixer.h"
+#include "helper.h"
+#include "power.h"
+
+#include "mixer_us16x08.h"
+
+#define COMP_INFOPUTGET_NOLOG
+
+static char comp_msg[] = {
+ CTLMSGHEAD_IN, /* default message head, equal to all mixers */
+ 0x91,
+ 0x02,
+ 0xf0, /* 0x08: Threshold db (8) (e0 ... 00) (+-0dB -- -32dB) x-32 */
+ 0x92,
+ 0x02,
+ 0x0a, /* 0x0b: Ratio (0a,0b,0d,0f,11,14,19,1e,23,28,32,3c,50,a0,ff) */
+ 0x93,
+ 0x02,
+ 0x02, /* 0x0e: Attack (0x02 ... 0xc0) (2ms ... 200ms) */
+ 0x94,
+ 0x02,
+ 0x01, /* 0x11: Release (0x01 ... 0x64) (10ms ... 1000ms) x*10 */
+ 0x95,
+ 0x02,
+ 0x03, /* 0x14: gain (0 ... 20) (0dB .. 20dB) */
+ 0x96,
+ 0x02,
+ 0x01,
+ 0x97,
+ 0x02,
+ 0x01, /* 0x1a: main Comp switch (0 ... 1) (off ... on)) */
+ 0x00,
+ 0x00
+};
+
+static char ratio_map[] = {
+ 0x0a, 0x0b, 0x0d, 0x0f, 0x11, 0x14, 0x19, 0x1e,
+ 0x23, 0x28, 0x32, 0x3c, 0x50, 0xa0, 0xff
+};
+
+struct snd_us16x08_comp_store *comp_store;
+
+int snd_us16x08_compswitch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->count = 1;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->value.integer.max = 1;
+ uinfo->value.integer.min = 0;
+ return 0;
+}
+
+static int snd_us16x08_comp_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int val = 0;
+ int bias = (kcontrol->private_value >> 24) & 0xff;
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_comp_store *store =
+ ((struct snd_us16x08_comp_store *) elem->private_data);
+ int index = ucontrol->id.index;
+
+
+ switch (elem->head.id) {
+ case SND_US16X08_ID_COMP_THRESHOLD:
+ val = store->valThreshold[index];
+ dev_info(&chip->dev->dev,
+ "snd_us16x08_comp_get name:Threshold index: %d val:%d",
+ index, val);
+ break;
+ case SND_US16X08_ID_COMP_RATIO:
+ val = store->valRatio[index];
+ dev_info(&chip->dev->dev,
+ "snd_us16x08_comp_get name:Ratio index: %d val:%d",
+ index, val);
+ break;
+ case SND_US16X08_ID_COMP_ATTACK:
+ val = store->valAttack[index] - bias;
+ dev_info(&chip->dev->dev,
+ "snd_us16x08_comp_get name:Attack index: %d val:%d",
+ index, val);
+ break;
+ case SND_US16X08_ID_COMP_RELEASE:
+ val = store->valRelease[index] - bias;
+ dev_info(&chip->dev->dev,
+ "snd_us16x08_comp_get name:Release index: %d val:%d",
+ index, val);
+ break;
+ case SND_US16X08_ID_COMP_GAIN:
+ val = store->valGain[index];
+ dev_info(&chip->dev->dev,
+ "snd_us16x08_comp_get name:Gain index: %d val:%d",
+ index, val);
+ break;
+ case SND_US16X08_ID_COMP_SWITCH:
+ val = store->valSwitch[index];
+ dev_info(&chip->dev->dev,
+ "snd_us16x08_comp_get name:Switch index: %d val:%d",
+ index, val);
+ break;
+ }
+ ucontrol->value.integer.value[0] = val;
+
+ return 0;
+}
+
+static int snd_us16x08_comp_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_comp_store *store =
+ ((struct snd_us16x08_comp_store *) elem->private_data);
+ int index = ucontrol->id.index;
+
+ char buf[sizeof(comp_msg)];
+ int val, err = 0;
+ int bias = SND_US16X08_KCBIAS(kcontrol);
+
+ memcpy(buf, comp_msg, sizeof(comp_msg));
+
+ val = ucontrol->value.integer.value[0];
+
+ switch (elem->head.id) {
+ case SND_US16X08_ID_COMP_THRESHOLD:
+ store->valThreshold[index] = val;
+ break;
+ case SND_US16X08_ID_COMP_RATIO:
+ store->valRatio[index] = val;
+ break;
+ case SND_US16X08_ID_COMP_ATTACK:
+ store->valAttack[index] = val + bias;
+ break;
+ case SND_US16X08_ID_COMP_RELEASE:
+ store->valRelease[index] = val + bias;
+ break;
+ case SND_US16X08_ID_COMP_GAIN:
+ store->valGain[index] = val;
+ break;
+ case SND_US16X08_ID_COMP_SWITCH:
+ store->valSwitch[index] = val;
+ break;
+ }
+
+ buf[8] = store->valThreshold[index] - SND_US16X08_COMP_THRESHOLD_BIAS;
+ buf[11] = ratio_map[store->valRatio[index]];
+ buf[14] = store->valAttack[index];
+ buf[17] = store->valRelease[index];
+ buf[20] = store->valGain[index];
+ buf[26] = store->valSwitch[index];
+
+ buf[5] = index + 1;
+
+ err = snd_us16x08_send_urb(chip, buf, sizeof(comp_msg));
+
+ return 1;
+}
+
+static struct snd_kcontrol_new snd_us16x08_compswitch_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_compswitch_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value = ((SND_US16X08_NO_BIAS << 24) | /*bias*/
+ (1 << 16) | /*step*/
+ (0 << 8) | /*min*/
+ (1)), /*max*/
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_threshold_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value = ((SND_US16X08_COMP_THRESHOLD_BIAS << 24) | /*bias*/
+ (1 << 16) | /*step*/
+ (0 << 8) | /*min*/
+ (0x20)), /*max*/
+};
+static struct snd_kcontrol_new snd_us16x08_comp_ratio_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value = ((SND_US16X08_NO_BIAS << 24) | /*bias*/
+ (1 << 16) | /*step*/
+ (0 << 8) | /*min*/
+ (sizeof(ratio_map) - 1)), /*max*/
+};
+static struct snd_kcontrol_new snd_us16x08_comp_gain_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x14),
+};
+static struct snd_kcontrol_new snd_us16x08_comp_attack_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value =
+ SND_US16X08_KCSET(SND_US16X08_COMP_ATTACK_BIAS, 1, 0, 0xc6),
+};
+static struct snd_kcontrol_new snd_us16x08_comp_release_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value =
+ SND_US16X08_KCSET(SND_US16X08_COMP_RELEASE_BIAS, 1, 0, 0x63),
+};
+
+struct snd_us16x08_comp_store *snd_us16x08_create_comp_store(void)
+{
+ int i = 0;
+ struct snd_us16x08_comp_store *tmp =
+ kmalloc(sizeof(struct snd_us16x08_comp_store), GFP_KERNEL);
+
+ for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
+ tmp->valThreshold[i] = 0x20; /* 0dB */
+ tmp->valRatio[i] = 0x00; /* 1:1 */
+ tmp->valGain[i] = 0x00; /* 0dB */
+ tmp->valSwitch[i] = 0x00; /* on */
+ tmp->valAttack[i] = 0x02; /* 2ms */
+ tmp->valRelease[i] = 0x01; /* 10ms */
+ }
+ return tmp;
+}
+
+int snd_us16x08_controls_create_comp(struct usb_mixer_interface *mixer)
+{
+
+ int err;
+ char name[64];
+ struct usb_mixer_elem_info *elem;
+
+ comp_store = snd_us16x08_create_comp_store();
+
+ snprintf(name, sizeof(name), "A Comp");
+ err = add_new_ctl(mixer, &snd_us16x08_compswitch_ctl,
+ SND_US16X08_ID_COMP_SWITCH, 0x00, 0, USB_MIXER_U8, 1,
+ name, (void *) comp_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "B Thresh");
+ err = add_new_ctl(mixer, &snd_us16x08_comp_threshold_ctl,
+ SND_US16X08_ID_COMP_THRESHOLD, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) comp_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "C Ratio");
+ err = add_new_ctl(mixer, &snd_us16x08_comp_ratio_ctl,
+ SND_US16X08_ID_COMP_RATIO, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) comp_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "D Attack");
+ err = add_new_ctl(mixer, &snd_us16x08_comp_attack_ctl,
+ SND_US16X08_ID_COMP_ATTACK, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) comp_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "E Release");
+ err = add_new_ctl(mixer, &snd_us16x08_comp_release_ctl,
+ SND_US16X08_ID_COMP_RELEASE, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) comp_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "F Gain");
+ err = add_new_ctl(mixer, &snd_us16x08_comp_gain_ctl,
+ SND_US16X08_ID_COMP_GAIN, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) comp_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ return err;
+}
+
+struct snd_us16x08_comp_store* get_comp_store(void)
+{
+ return comp_store;
+}
\ No newline at end of file
diff --git a/sound/usb/mixer_us16x08_eq.c b/sound/usb/mixer_us16x08_eq.c
new file mode 100644
index 0000000..dea2dfb
--- /dev/null
+++ b/sound/usb/mixer_us16x08_eq.c
@@ -0,0 +1,407 @@
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/audio-v2.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+
+
+#include "usbaudio.h"
+#include "mixer.h"
+
+#include "mixer_us16x08.h"
+
+
+#define EQ_INFOPUTGET_NOLOG
+
+static char eqs_msq[] = {
+ CTLMSGHEAD_IN, /* default message head, equal to all mixers */
+ 0x51, /* 0x06: Controller ID */
+ 0x02,
+ 0x04, /* 0x08: EQ set num (0x01..0x04) (LOW, LOWMID, HIGHMID, HIGH)) */
+ 0x52,
+ 0x02,
+ 0x0c, /* 0x0b: value dB (0 ... 12) (-12db .. +12db) x-6 */
+ 0x53,
+ 0x02,
+ 0x0f, /* 0x0e: value freq (32-47) (1.7kHz..18kHz) */
+ 0x54,
+ 0x02,
+ 0x02, /* 0x11: band width (0-6) (Q16-Q0.25) 2^x/4 (EQ xxMID only) */
+ 0x55,
+ 0x02,
+ 0x01, /* 0x14: main EQ switch (0 ... 1) (off ... on)) */
+ 0x00,
+ 0x00
+};
+
+int snd_us16x08_eqswitch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->count = 1;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->value.integer.max = 1;
+ uinfo->value.integer.min = 0;
+ return 0;
+}
+
+static int snd_us16x08_eqswitch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int val = 0;
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_us16x08_eq_all_store *store =
+ ((struct snd_us16x08_eq_all_store *) elem->private_data);
+ int index = ucontrol->id.index;
+
+ val = store->low_store->valSwitch[index];
+ ucontrol->value.integer.value[0] = val;
+
+ return 0;
+}
+
+static int snd_us16x08_eqswitch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_eq_all_store *store =
+ ((struct snd_us16x08_eq_all_store *) elem->private_data);
+ int index = ucontrol->id.index;
+
+ char buf[sizeof(eqs_msq)];
+ int val, err = 0;
+
+ val = ucontrol->value.integer.value[0];
+
+ memcpy(buf, eqs_msq, sizeof(eqs_msq));
+
+ store->low_store->valSwitch[index] = val;
+ store->midlow_store->valSwitch[index] = val;
+ store->midhigh_store->valSwitch[index] = val;
+ store->high_store->valSwitch[index] = val;
+
+ buf[5] = index + 1;
+
+ buf[20] = store->low_store->valSwitch[index];
+ buf[17] = store->low_store->valWidth[index];
+ buf[14] = store->low_store->valFreq[index];
+ buf[11] = store->low_store->valdB[index];
+ buf[8] = 0x01;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
+
+ udelay(15000);
+ buf[20] = store->midlow_store->valSwitch[index];
+ buf[17] = store->midlow_store->valWidth[index];
+ buf[14] = store->midlow_store->valFreq[index];
+ buf[11] = store->midlow_store->valdB[index];
+ buf[8] = 0x02;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
+
+ udelay(15000);
+ buf[20] = store->midhigh_store->valSwitch[index];
+ buf[17] = store->midhigh_store->valWidth[index];
+ buf[14] = store->midhigh_store->valFreq[index];
+ buf[11] = store->midhigh_store->valdB[index];
+ buf[8] = 0x03;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
+
+ udelay(15000);
+ buf[20] = store->high_store->valSwitch[index];
+ buf[17] = store->high_store->valWidth[index];
+ buf[14] = store->high_store->valFreq[index];
+ buf[11] = store->high_store->valdB[index];
+ buf[8] = 0x04;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
+
+ return 1;
+}
+
+static int snd_us16x08_eq_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int val = 0;
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_us16x08_eq_store *store =
+ ((struct snd_us16x08_eq_store *) elem->private_data);
+ int index = ucontrol->id.index;
+
+
+ switch (elem->head.id & 0xf0) {
+ case 0x00:
+ val = store->valdB[index];
+ break;
+ case 0x10:
+ val = store->valFreq[index] -
+ ((kcontrol->private_value >> 24) & 0xff);
+ break;
+ case 0x20:
+ val = store->valWidth[index];
+ break;
+ }
+ ucontrol->value.integer.value[0] = val;
+
+ return 0;
+}
+
+static int snd_us16x08_eq_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_eq_store *store =
+ ((struct snd_us16x08_eq_store *) elem->private_data);
+ int index = ucontrol->id.index;
+
+ char buf[sizeof(eqs_msq)];
+ int val, err = 0;
+
+ memcpy(buf, eqs_msq, sizeof(eqs_msq));
+
+ val = ucontrol->value.integer.value[0] +
+ ((kcontrol->private_value >> 24) & 0xff);
+
+ switch (elem->head.id & 0xf0) {
+ case 0x00: /* level dB */
+ store->valdB[index] = val;
+ break;
+ case 0x10:
+ store->valFreq[index] = val;
+ break;
+ case 0x20:
+ store->valWidth[index] = val;
+ break;
+ }
+
+ buf[20] = store->valSwitch[index];
+ buf[17] = store->valWidth[index];
+ buf[14] = store->valFreq[index];
+ buf[11] = store->valdB[index];
+
+ buf[5] = index + 1;
+
+ buf[8] = (elem->head.id & 0x0F);
+ err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
+
+ return 1;
+}
+
+static struct snd_kcontrol_new snd_us16x08_eqlevel_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_eq_get,
+ .put = snd_us16x08_eq_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 24),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eqLowFreq_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_eq_get,
+ .put = snd_us16x08_eq_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x1F),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eqMidFreq_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_eq_get,
+ .put = snd_us16x08_eq_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x3F),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eqMidWidth_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_eq_get,
+ .put = snd_us16x08_eq_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x06),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eqHighFreq_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_eq_get,
+ .put = snd_us16x08_eq_put,
+ .private_value =
+ SND_US16X08_KCSET(SND_US16X08_EQ_HIGHFREQ_BIAS, 1, 0, 0x1F),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eqswitch_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "",
+ .count = 16,
+ .info = snd_us16x08_eqswitch_info,
+ .get = snd_us16x08_eqswitch_get,
+ .put = snd_us16x08_eqswitch_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1),
+};
+
+struct snd_us16x08_eq_store *snd_us16x08_create_eq_store(int index)
+{
+ int i = 0;
+ struct snd_us16x08_eq_store *tmp =
+ kmalloc(sizeof(struct snd_us16x08_eq_store), GFP_KERNEL);
+
+ for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
+ switch (index) {
+ case 0x01: /* EQ Low */
+ tmp->valdB[i] = 0x0c;
+ tmp->valFreq[i] = 0x05;
+ tmp->valWidth[i] = 0xff;
+ tmp->valSwitch[i] = 0x01; /* on */
+ break;
+ case 0x02: /* EQ Mid low */
+ tmp->valdB[i] = 0x0c;
+ tmp->valFreq[i] = 0x0e;
+ tmp->valWidth[i] = 0x02;
+ tmp->valSwitch[i] = 0x01; /* on */
+ break;
+ case 0x03: /* EQ Mid High */
+ tmp->valdB[i] = 0x0c;
+ tmp->valFreq[i] = 0x1b;
+ tmp->valWidth[i] = 0x02;
+ tmp->valSwitch[i] = 0x01; /* on */
+ break;
+ case 0x04: /* EQ Mid Low */
+ tmp->valdB[i] = 0x0c;
+ tmp->valFreq[i] = 0x2f;
+ tmp->valWidth[i] = 0xff;
+ tmp->valSwitch[i] = 0x01; /* on */
+ break;
+ }
+ }
+ return tmp;
+}
+
+void snd_us16x08_free_eq_store(struct snd_kcontrol *kctl)
+{
+ snd_usb_mixer_elem_free(kctl);
+}
+
+int snd_us16x08_controls_create_eq(struct usb_mixer_interface *mixer)
+{
+
+ int err;
+ char name[64];
+ struct usb_mixer_elem_info *elem;
+
+ struct snd_us16x08_eq_store *eq_low_store =
+ snd_us16x08_create_eq_store(0x01);
+ struct snd_us16x08_eq_store *eq_midlow_store =
+ snd_us16x08_create_eq_store(0x02);
+ struct snd_us16x08_eq_store *eq_midhigh_store =
+ snd_us16x08_create_eq_store(0x03);
+ struct snd_us16x08_eq_store *eq_high_store =
+ snd_us16x08_create_eq_store(0x04);
+ struct snd_us16x08_eq_all_store *eq_all_store =
+ kmalloc(sizeof(struct snd_us16x08_eq_all_store), GFP_KERNEL);
+
+ eq_all_store->low_store = eq_low_store;
+ eq_all_store->midlow_store = eq_midlow_store;
+ eq_all_store->midhigh_store = eq_midhigh_store;
+ eq_all_store->high_store = eq_high_store;
+
+
+ snprintf(name, sizeof(name), "5 Low");
+ err = add_new_ctl(mixer, &snd_us16x08_eqlevel_ctl,
+ SND_US16X08_ID_EQLOWLEVEL, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) eq_low_store, snd_us16x08_free_eq_store, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "51 LowFreq");
+ err = add_new_ctl(mixer, &snd_us16x08_eqLowFreq_ctl,
+ SND_US16X08_ID_EQLOWFREQ, 0x00, 0,
+ USB_MIXER_U8, 1, name, (void *) eq_low_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+
+
+ snprintf(name, sizeof(name), "6 MLow");
+ err = add_new_ctl(mixer, &snd_us16x08_eqlevel_ctl,
+ SND_US16X08_ID_EQLOWMIDLEVEL, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) eq_midlow_store, snd_us16x08_free_eq_store, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "61 MLowFreq");
+ err = add_new_ctl(mixer, &snd_us16x08_eqMidFreq_ctl,
+ SND_US16X08_ID_EQLOWMIDFREQ, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) eq_midlow_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "62 MLowWidth");
+ err = add_new_ctl(mixer, &snd_us16x08_eqMidWidth_ctl,
+ SND_US16X08_ID_EQLOWMIDWIDTH, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) eq_midlow_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "7 MHigh");
+ err = add_new_ctl(mixer, &snd_us16x08_eqlevel_ctl,
+ SND_US16X08_ID_EQHIGHMIDLEVEL, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) eq_midhigh_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "71 MHiFreq");
+ err = add_new_ctl(mixer, &snd_us16x08_eqMidFreq_ctl,
+ SND_US16X08_ID_EQHIGHMIDFREQ, 0x00, 0,
+ USB_MIXER_U8, 1, name, (void *) eq_midhigh_store, NULL,
+ &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "72 MHiWidth");
+ err = add_new_ctl(mixer, &snd_us16x08_eqMidWidth_ctl,
+ SND_US16X08_ID_EQHIGHMIDWIDTH, 0x00, 0,
+ USB_MIXER_U8, 1, name, (void *) eq_midhigh_store, NULL,
+ &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "8 High");
+ err = add_new_ctl(mixer, &snd_us16x08_eqlevel_ctl,
+ SND_US16X08_ID_EQHIGHLEVEL, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) eq_high_store, snd_us16x08_free_eq_store, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "81 HighFreq");
+ err = add_new_ctl(mixer, &snd_us16x08_eqHighFreq_ctl,
+ SND_US16X08_ID_EQHIGHFREQ, 0x00, 0, USB_MIXER_U8, 1, name,
+ (void *) eq_high_store, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ snprintf(name, sizeof(name), "9 EQ");
+ err = add_new_ctl(mixer, &snd_us16x08_eqswitch_ctl,
+ SND_US16X08_ID_EQENABLE, 0x00, 0, USB_MIXER_BOOLEAN, 1, name,
+ (void *) eq_all_store, NULL,
+ &elem);
+ if (err < 0)
+ return err;
+
+
+ return 0;
+}
2
3
Re: [alsa-devel] [linux-sunxi] Re: [PATCH v3 05/10] arm: dts: sun8i: split Allwinner H3 .dtsi
by Icenowy Zheng 30 Jan '17
by Icenowy Zheng 30 Jan '17
30 Jan '17
2017年1月30日 09:42于 André Przywara <andre.przywara(a)arm.com>写道:
>
> On 29/01/17 02:33, Icenowy Zheng wrote:
> > From: Andre Przywara <andre.przywara(a)arm.com>
>
> (Adding DT folks to CC:)
>
> see below ...
>
> > The new Allwinner H5 SoC is pin-compatible to the H3 SoC, but with the
> > Cortex-A7 cores replaced by Cortex-A53 cores and the MMC controller
> > updated. So we should really share almost the whole .dtsi.
> > In preparation for that move the peripheral parts of the existing
> > sun8i-h3.dtsi into a new sun8i-h3-h5.dtsi.
> > The actual sun8i-h3.dtsi then includes that and defines the H3 specific
> > parts on top of it.
> > On the way get rid of skeleton.dtsi, as recommended in that very file.
> >
> > Signed-off-by: Andre Przywara <andre.przywara(a)arm.com>
> > [Icenowy: also split out mmc, as well as pio and ccu's compatible]
> > Signed-off-by: Icenowy Zheng <icenowy(a)aosc.xyz>
> > ---
> > Changes in v3:
> > - Use label-based syntax to reference nodes in H3 DTSI file.
> > Changes in v2:
> > - Rebase on current linux-next (because of the add of audio codec)
> >
> > arch/arm/boot/dts/sun8i-h3.dtsi | 571 +++----------------------------------
> > arch/arm/boot/dts/sunxi-h3-h5.dtsi | 557 ++++++++++++++++++++++++++++++++++++
> > 2 files changed, 598 insertions(+), 530 deletions(-)
> > create mode 100644 arch/arm/boot/dts/sunxi-h3-h5.dtsi
> >
> > diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
> > index 08fd0860bb6b..f3a3033789b9 100644
> > --- a/arch/arm/boot/dts/sun8i-h3.dtsi
> > +++ b/arch/arm/boot/dts/sun8i-h3.dtsi
> > @@ -40,12 +40,7 @@
> > * OTHER DEALINGS IN THE SOFTWARE.
> > */
> >
> > -#include "skeleton.dtsi"
> > -
> > -#include <dt-bindings/clock/sun8i-h3-ccu.h>
> > -#include <dt-bindings/interrupt-controller/arm-gic.h>
> > -#include <dt-bindings/pinctrl/sun4i-a10.h>
> > -#include <dt-bindings/reset/sun8i-h3-ccu.h>
> > +#include "sunxi-h3-h5.dtsi"
> >
> > / {
> > interrupt-parent = <&gic>;
> > @@ -87,489 +82,7 @@
> > <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
> > };
> >
> > - clocks {
> > - #address-cells = <1>;
> > - #size-cells = <1>;
> > - ranges;
> > -
> > - osc24M: osc24M_clk {
> > - #clock-cells = <0>;
> > - compatible = "fixed-clock";
> > - clock-frequency = <24000000>;
> > - clock-output-names = "osc24M";
> > - };
> > -
> > - osc32k: osc32k_clk {
> > - #clock-cells = <0>;
> > - compatible = "fixed-clock";
> > - clock-frequency = <32768>;
> > - clock-output-names = "osc32k";
> > - };
> > -
> > - apb0: apb0_clk {
> > - compatible = "fixed-factor-clock";
> > - #clock-cells = <0>;
> > - clock-div = <1>;
> > - clock-mult = <1>;
> > - clocks = <&osc24M>;
> > - clock-output-names = "apb0";
> > - };
> > -
> > - apb0_gates: clk@01f01428 {
> > - compatible = "allwinner,sun8i-h3-apb0-gates-clk",
> > - "allwinner,sun4i-a10-gates-clk";
> > - reg = <0x01f01428 0x4>;
> > - #clock-cells = <1>;
> > - clocks = <&apb0>;
> > - clock-indices = <0>, <1>;
> > - clock-output-names = "apb0_pio", "apb0_ir";
> > - };
> > -
> > - ir_clk: ir_clk@01f01454 {
> > - compatible = "allwinner,sun4i-a10-mod0-clk";
> > - reg = <0x01f01454 0x4>;
> > - #clock-cells = <0>;
> > - clocks = <&osc32k>, <&osc24M>;
> > - clock-output-names = "ir";
> > - };
> > - };
> > -
> > soc {
> > - compatible = "simple-bus";
> > - #address-cells = <1>;
> > - #size-cells = <1>;
> > - ranges;
> > -
> > - dma: dma-controller@01c02000 {
> > - compatible = "allwinner,sun8i-h3-dma";
> > - reg = <0x01c02000 0x1000>;
> > - interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_DMA>;
> > - resets = <&ccu RST_BUS_DMA>;
> > - #dma-cells = <1>;
> > - };
> > -
> > - mmc0: mmc@01c0f000 {
> > - compatible = "allwinner,sun7i-a20-mmc";
> > - reg = <0x01c0f000 0x1000>;
> > - clocks = <&ccu CLK_BUS_MMC0>,
> > - <&ccu CLK_MMC0>,
> > - <&ccu CLK_MMC0_OUTPUT>,
> > - <&ccu CLK_MMC0_SAMPLE>;
> > - clock-names = "ahb",
> > - "mmc",
> > - "output",
> > - "sample";
> > - resets = <&ccu RST_BUS_MMC0>;
> > - reset-names = "ahb";
> > - interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
> > - status = "disabled";
> > - #address-cells = <1>;
> > - #size-cells = <0>;
> > - };
> > -
> > - mmc1: mmc@01c10000 {
> > - compatible = "allwinner,sun7i-a20-mmc";
> > - reg = <0x01c10000 0x1000>;
> > - clocks = <&ccu CLK_BUS_MMC1>,
> > - <&ccu CLK_MMC1>,
> > - <&ccu CLK_MMC1_OUTPUT>,
> > - <&ccu CLK_MMC1_SAMPLE>;
> > - clock-names = "ahb",
> > - "mmc",
> > - "output",
> > - "sample";
> > - resets = <&ccu RST_BUS_MMC1>;
> > - reset-names = "ahb";
> > - interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
> > - status = "disabled";
> > - #address-cells = <1>;
> > - #size-cells = <0>;
> > - };
> > -
> > - mmc2: mmc@01c11000 {
> > - compatible = "allwinner,sun7i-a20-mmc";
> > - reg = <0x01c11000 0x1000>;
> > - clocks = <&ccu CLK_BUS_MMC2>,
> > - <&ccu CLK_MMC2>,
> > - <&ccu CLK_MMC2_OUTPUT>,
> > - <&ccu CLK_MMC2_SAMPLE>;
> > - clock-names = "ahb",
> > - "mmc",
> > - "output",
> > - "sample";
> > - resets = <&ccu RST_BUS_MMC2>;
> > - reset-names = "ahb";
> > - interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
> > - status = "disabled";
> > - #address-cells = <1>;
> > - #size-cells = <0>;
> > - };
> > -
> > - usbphy: phy@01c19400 {
> > - compatible = "allwinner,sun8i-h3-usb-phy";
> > - reg = <0x01c19400 0x2c>,
> > - <0x01c1a800 0x4>,
> > - <0x01c1b800 0x4>,
> > - <0x01c1c800 0x4>,
> > - <0x01c1d800 0x4>;
> > - reg-names = "phy_ctrl",
> > - "pmu0",
> > - "pmu1",
> > - "pmu2",
> > - "pmu3";
> > - clocks = <&ccu CLK_USB_PHY0>,
> > - <&ccu CLK_USB_PHY1>,
> > - <&ccu CLK_USB_PHY2>,
> > - <&ccu CLK_USB_PHY3>;
> > - clock-names = "usb0_phy",
> > - "usb1_phy",
> > - "usb2_phy",
> > - "usb3_phy";
> > - resets = <&ccu RST_USB_PHY0>,
> > - <&ccu RST_USB_PHY1>,
> > - <&ccu RST_USB_PHY2>,
> > - <&ccu RST_USB_PHY3>;
> > - reset-names = "usb0_reset",
> > - "usb1_reset",
> > - "usb2_reset",
> > - "usb3_reset";
> > - status = "disabled";
> > - #phy-cells = <1>;
> > - };
> > -
> > - ehci1: usb@01c1b000 {
> > - compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
> > - reg = <0x01c1b000 0x100>;
> > - interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>;
> > - resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
> > - phys = <&usbphy 1>;
> > - phy-names = "usb";
> > - status = "disabled";
> > - };
> > -
> > - ohci1: usb@01c1b400 {
> > - compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
> > - reg = <0x01c1b400 0x100>;
> > - interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>,
> > - <&ccu CLK_USB_OHCI1>;
> > - resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
> > - phys = <&usbphy 1>;
> > - phy-names = "usb";
> > - status = "disabled";
> > - };
> > -
> > - ehci2: usb@01c1c000 {
> > - compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
> > - reg = <0x01c1c000 0x100>;
> > - interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>;
> > - resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
> > - phys = <&usbphy 2>;
> > - phy-names = "usb";
> > - status = "disabled";
> > - };
> > -
> > - ohci2: usb@01c1c400 {
> > - compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
> > - reg = <0x01c1c400 0x100>;
> > - interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>,
> > - <&ccu CLK_USB_OHCI2>;
> > - resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
> > - phys = <&usbphy 2>;
> > - phy-names = "usb";
> > - status = "disabled";
> > - };
> > -
> > - ehci3: usb@01c1d000 {
> > - compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
> > - reg = <0x01c1d000 0x100>;
> > - interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>;
> > - resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
> > - phys = <&usbphy 3>;
> > - phy-names = "usb";
> > - status = "disabled";
> > - };
> > -
> > - ohci3: usb@01c1d400 {
> > - compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
> > - reg = <0x01c1d400 0x100>;
> > - interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>,
> > - <&ccu CLK_USB_OHCI3>;
> > - resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
> > - phys = <&usbphy 3>;
> > - phy-names = "usb";
> > - status = "disabled";
> > - };
> > -
> > - ccu: clock@01c20000 {
> > - compatible = "allwinner,sun8i-h3-ccu";
> > - reg = <0x01c20000 0x400>;
> > - clocks = <&osc24M>, <&osc32k>;
> > - clock-names = "hosc", "losc";
> > - #clock-cells = <1>;
> > - #reset-cells = <1>;
> > - };
> > -
> > - pio: pinctrl@01c20800 {
> > - compatible = "allwinner,sun8i-h3-pinctrl";
> > - reg = <0x01c20800 0x400>;
> > - interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
> > - <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
> > - clock-names = "apb", "hosc", "losc";
> > - gpio-controller;
> > - #gpio-cells = <3>;
> > - interrupt-controller;
> > - #interrupt-cells = <3>;
> > -
> > - i2c0_pins: i2c0 {
> > - pins = "PA11", "PA12";
> > - function = "i2c0";
> > - };
> > -
> > - i2c1_pins: i2c1 {
> > - pins = "PA18", "PA19";
> > - function = "i2c1";
> > - };
> > -
> > - i2c2_pins: i2c2 {
> > - pins = "PE12", "PE13";
> > - function = "i2c2";
> > - };
> > -
> > - mmc0_pins_a: mmc0@0 {
> > - pins = "PF0", "PF1", "PF2", "PF3",
> > - "PF4", "PF5";
> > - function = "mmc0";
> > - drive-strength = <30>;
> > - bias-pull-up;
> > - };
> > -
> > - mmc0_cd_pin: mmc0_cd_pin@0 {
> > - pins = "PF6";
> > - function = "gpio_in";
> > - bias-pull-up;
> > - };
> > -
> > - mmc1_pins_a: mmc1@0 {
> > - pins = "PG0", "PG1", "PG2", "PG3",
> > - "PG4", "PG5";
> > - function = "mmc1";
> > - drive-strength = <30>;
> > - bias-pull-up;
> > - };
> > -
> > - mmc2_8bit_pins: mmc2_8bit {
> > - pins = "PC5", "PC6", "PC8",
> > - "PC9", "PC10", "PC11",
> > - "PC12", "PC13", "PC14",
> > - "PC15", "PC16";
> > - function = "mmc2";
> > - drive-strength = <30>;
> > - bias-pull-up;
> > - };
> > -
> > - spi0_pins: spi0 {
> > - pins = "PC0", "PC1", "PC2", "PC3";
> > - function = "spi0";
> > - };
> > -
> > - spi1_pins: spi1 {
> > - pins = "PA15", "PA16", "PA14", "PA13";
> > - function = "spi1";
> > - };
> > -
> > - uart0_pins_a: uart0@0 {
> > - pins = "PA4", "PA5";
> > - function = "uart0";
> > - };
> > -
> > - uart1_pins: uart1 {
> > - pins = "PG6", "PG7";
> > - function = "uart1";
> > - };
> > -
> > - uart1_rts_cts_pins: uart1_rts_cts {
> > - pins = "PG8", "PG9";
> > - function = "uart1";
> > - };
> > -
> > - uart2_pins: uart2 {
> > - pins = "PA0", "PA1";
> > - function = "uart2";
> > - };
> > -
> > - uart3_pins: uart3 {
> > - pins = "PA13", "PA14";
> > - function = "uart3";
> > - };
> > - };
> > -
> > - timer@01c20c00 {
> > - compatible = "allwinner,sun4i-a10-timer";
> > - reg = <0x01c20c00 0xa0>;
> > - interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
> > - <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&osc24M>;
> > - };
> > -
> > - spi0: spi@01c68000 {
> > - compatible = "allwinner,sun8i-h3-spi";
> > - reg = <0x01c68000 0x1000>;
> > - interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
> > - clock-names = "ahb", "mod";
> > - dmas = <&dma 23>, <&dma 23>;
> > - dma-names = "rx", "tx";
> > - pinctrl-names = "default";
> > - pinctrl-0 = <&spi0_pins>;
> > - resets = <&ccu RST_BUS_SPI0>;
> > - status = "disabled";
> > - #address-cells = <1>;
> > - #size-cells = <0>;
> > - };
> > -
> > - spi1: spi@01c69000 {
> > - compatible = "allwinner,sun8i-h3-spi";
> > - reg = <0x01c69000 0x1000>;
> > - interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
> > - clock-names = "ahb", "mod";
> > - dmas = <&dma 24>, <&dma 24>;
> > - dma-names = "rx", "tx";
> > - pinctrl-names = "default";
> > - pinctrl-0 = <&spi1_pins>;
> > - resets = <&ccu RST_BUS_SPI1>;
> > - status = "disabled";
> > - #address-cells = <1>;
> > - #size-cells = <0>;
> > - };
> > -
> > - wdt0: watchdog@01c20ca0 {
> > - compatible = "allwinner,sun6i-a31-wdt";
> > - reg = <0x01c20ca0 0x20>;
> > - interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
> > - };
> > -
> > - pwm: pwm@01c21400 {
> > - compatible = "allwinner,sun8i-h3-pwm";
> > - reg = <0x01c21400 0x8>;
> > - clocks = <&osc24M>;
> > - #pwm-cells = <3>;
> > - status = "disabled";
> > - };
> > -
> > - codec: codec@01c22c00 {
> > - #sound-dai-cells = <0>;
> > - compatible = "allwinner,sun8i-h3-codec";
> > - reg = <0x01c22c00 0x400>;
> > - interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
> > - clock-names = "apb", "codec";
> > - resets = <&ccu RST_BUS_CODEC>;
> > - dmas = <&dma 15>, <&dma 15>;
> > - dma-names = "rx", "tx";
> > - allwinner,codec-analog-controls = <&codec_analog>;
> > - status = "disabled";
> > - };
> > -
> > - uart0: serial@01c28000 {
> > - compatible = "snps,dw-apb-uart";
> > - reg = <0x01c28000 0x400>;
> > - interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> > - reg-shift = <2>;
> > - reg-io-width = <4>;
> > - clocks = <&ccu CLK_BUS_UART0>;
> > - resets = <&ccu RST_BUS_UART0>;
> > - dmas = <&dma 6>, <&dma 6>;
> > - dma-names = "rx", "tx";
> > - status = "disabled";
> > - };
> > -
> > - uart1: serial@01c28400 {
> > - compatible = "snps,dw-apb-uart";
> > - reg = <0x01c28400 0x400>;
> > - interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
> > - reg-shift = <2>;
> > - reg-io-width = <4>;
> > - clocks = <&ccu CLK_BUS_UART1>;
> > - resets = <&ccu RST_BUS_UART1>;
> > - dmas = <&dma 7>, <&dma 7>;
> > - dma-names = "rx", "tx";
> > - status = "disabled";
> > - };
> > -
> > - uart2: serial@01c28800 {
> > - compatible = "snps,dw-apb-uart";
> > - reg = <0x01c28800 0x400>;
> > - interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
> > - reg-shift = <2>;
> > - reg-io-width = <4>;
> > - clocks = <&ccu CLK_BUS_UART2>;
> > - resets = <&ccu RST_BUS_UART2>;
> > - dmas = <&dma 8>, <&dma 8>;
> > - dma-names = "rx", "tx";
> > - status = "disabled";
> > - };
> > -
> > - uart3: serial@01c28c00 {
> > - compatible = "snps,dw-apb-uart";
> > - reg = <0x01c28c00 0x400>;
> > - interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
> > - reg-shift = <2>;
> > - reg-io-width = <4>;
> > - clocks = <&ccu CLK_BUS_UART3>;
> > - resets = <&ccu RST_BUS_UART3>;
> > - dmas = <&dma 9>, <&dma 9>;
> > - dma-names = "rx", "tx";
> > - status = "disabled";
> > - };
> > -
> > - i2c0: i2c@01c2ac00 {
> > - compatible = "allwinner,sun6i-a31-i2c";
> > - reg = <0x01c2ac00 0x400>;
> > - interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_I2C0>;
> > - resets = <&ccu RST_BUS_I2C0>;
> > - pinctrl-names = "default";
> > - pinctrl-0 = <&i2c0_pins>;
> > - status = "disabled";
> > - #address-cells = <1>;
> > - #size-cells = <0>;
> > - };
> > -
> > - i2c1: i2c@01c2b000 {
> > - compatible = "allwinner,sun6i-a31-i2c";
> > - reg = <0x01c2b000 0x400>;
> > - interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_I2C1>;
> > - resets = <&ccu RST_BUS_I2C1>;
> > - pinctrl-names = "default";
> > - pinctrl-0 = <&i2c1_pins>;
> > - status = "disabled";
> > - #address-cells = <1>;
> > - #size-cells = <0>;
> > - };
> > -
> > - i2c2: i2c@01c2b400 {
> > - compatible = "allwinner,sun6i-a31-i2c";
> > - reg = <0x01c2b000 0x400>;
> > - interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&ccu CLK_BUS_I2C2>;
> > - resets = <&ccu RST_BUS_I2C2>;
> > - pinctrl-names = "default";
> > - pinctrl-0 = <&i2c2_pins>;
> > - status = "disabled";
> > - #address-cells = <1>;
> > - #size-cells = <0>;
> > - };
> > -
> > gic: interrupt-controller@01c81000 {
> > compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
> > reg = <0x01c81000 0x1000>,
> > @@ -580,51 +93,49 @@
> > #interrupt-cells = <3>;
> > interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
> > };
> > + };
> > +};
> >
> > - rtc: rtc@01f00000 {
> > - compatible = "allwinner,sun6i-a31-rtc";
> > - reg = <0x01f00000 0x54>;
> > - interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
> > - <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
> > - };
> > -
> > - apb0_reset: reset@01f014b0 {
> > - reg = <0x01f014b0 0x4>;
> > - compatible = "allwinner,sun6i-a31-clock-reset";
> > - #reset-cells = <1>;
> > - };
> > +&ccu {
> > + compatible = "allwinner,sun8i-h3-ccu";
> > +};
>
> I believe this kind of sharing nodes is a bit frowned upon in connection
> with sharing .dtsi's. If the compatible name differs, I think it
> deserves to be a separate node spelt out in each SoC's .dtsi.
> This also makes the DT more readable, since a reader doesn't have to
> refer to two files to see what's in that node.
For such a device tree, see sun8i-a23-a33.c .
>
> >
> > - codec_analog: codec-analog@01f015c0 {
> > - compatible = "allwinner,sun8i-h3-codec-analog";
> > - reg = <0x01f015c0 0x4>;
> > - };
> > +&mmc0 {
> > + compatible = "allwinner,sun7i-a20-mmc";
> > + clocks = <&ccu CLK_BUS_MMC0>,
> > + <&ccu CLK_MMC0>,
> > + <&ccu CLK_MMC0_OUTPUT>,
> > + <&ccu CLK_MMC0_SAMPLE>;
> > + clock-names = "ahb",
> > + "mmc",
> > + "output",
> > + "sample";
>
> This applies even more here, since the MMC controllers also have
> different clock requirements.
>
> So why can't we just leave the CCU, MMC and possibly the pinctrl nodes
> completely out of the shared h3-h5.dtsi and introduce them from scratch
> in the SoC specific .dtsi?
>
> I think we still have enough identical nodes to justify this kind of
> .dtsi sharing.
>
> Cheers,
> Andre.
>
> > +};
> >
> > - ir: ir@01f02000 {
> > - compatible = "allwinner,sun5i-a13-ir";
> > - clocks = <&apb0_gates 1>, <&ir_clk>;
> > - clock-names = "apb", "ir";
> > - resets = <&apb0_reset 1>;
> > - interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> > - reg = <0x01f02000 0x40>;
> > - status = "disabled";
> > - };
> > +&mmc1 {
> > + compatible = "allwinner,sun7i-a20-mmc";
> > + clocks = <&ccu CLK_BUS_MMC1>,
> > + <&ccu CLK_MMC1>,
> > + <&ccu CLK_MMC1_OUTPUT>,
> > + <&ccu CLK_MMC1_SAMPLE>;
> > + clock-names = "ahb",
> > + "mmc",
> > + "output",
> > + "sample";
> > +};
> >
> > - r_pio: pinctrl@01f02c00 {
> > - compatible = "allwinner,sun8i-h3-r-pinctrl";
> > - reg = <0x01f02c00 0x400>;
> > - interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
> > - clocks = <&apb0_gates 0>, <&osc24M>, <&osc32k>;
> > - clock-names = "apb", "hosc", "losc";
> > - resets = <&apb0_reset 0>;
> > - gpio-controller;
> > - #gpio-cells = <3>;
> > - interrupt-controller;
> > - #interrupt-cells = <3>;
> > +&mmc2 {
> > + compatible = "allwinner,sun7i-a20-mmc";
> > + clocks = <&ccu CLK_BUS_MMC2>,
> > + <&ccu CLK_MMC2>,
> > + <&ccu CLK_MMC2_OUTPUT>,
> > + <&ccu CLK_MMC2_SAMPLE>;
> > + clock-names = "ahb",
> > + "mmc",
> > + "output",
> > + "sample";
> > +};
> >
> > - ir_pins_a: ir@0 {
> > - pins = "PL11";
> > - function = "s_cir_rx";
> > - };
> > - };
> > - };
> > +&pio {
> > + compatible = "allwinner,sun8i-h3-pinctrl";
> > };
> > diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
> > new file mode 100644
> > index 000000000000..4a57c65e8869
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
> > @@ -0,0 +1,557 @@
> > +/*
> > + * Copyright (C) 2015 Jens Kuske <jenskuske(a)gmail.com>
> > + *
> > + * This file is dual-licensed: you can use it either under the terms
> > + * of the GPL or the X11 license, at your option. Note that this dual
> > + * licensing only applies to this file, and not this project as a
> > + * whole.
> > + *
> > + * a) This file is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation; either version 2 of the
> > + * License, or (at your option) any later version.
> > + *
> > + * This file is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * Or, alternatively,
> > + *
> > + * b) Permission is hereby granted, free of charge, to any person
> > + * obtaining a copy of this software and associated documentation
> > + * files (the "Software"), to deal in the Software without
> > + * restriction, including without limitation the rights to use,
> > + * copy, modify, merge, publish, distribute, sublicense, and/or
> > + * sell copies of the Software, and to permit persons to whom the
> > + * Software is furnished to do so, subject to the following
> > + * conditions:
> > + *
> > + * The above copyright notice and this permission notice shall be
> > + * included in all copies or substantial portions of the Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> > + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> > + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> > + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> > + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> > + * OTHER DEALINGS IN THE SOFTWARE.
> > + */
> > +
> > +#include <dt-bindings/clock/sunxi-h3-h5-ccu.h>
> > +#include <dt-bindings/interrupt-controller/arm-gic.h>
> > +#include <dt-bindings/pinctrl/sun4i-a10.h>
> > +#include <dt-bindings/reset/sunxi-h3-h5-ccu.h>
> > +
> > +/ {
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > +
> > + clocks {
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > + ranges;
> > +
> > + osc24M: osc24M_clk {
> > + #clock-cells = <0>;
> > + compatible = "fixed-clock";
> > + clock-frequency = <24000000>;
> > + clock-output-names = "osc24M";
> > + };
> > +
> > + osc32k: osc32k_clk {
> > + #clock-cells = <0>;
> > + compatible = "fixed-clock";
> > + clock-frequency = <32768>;
> > + clock-output-names = "osc32k";
> > + };
> > +
> > + apb0: apb0_clk {
> > + compatible = "fixed-factor-clock";
> > + #clock-cells = <0>;
> > + clock-div = <1>;
> > + clock-mult = <1>;
> > + clocks = <&osc24M>;
> > + clock-output-names = "apb0";
> > + };
> > +
> > + apb0_gates: clk@01f01428 {
> > + compatible = "allwinner,sun8i-h3-apb0-gates-clk",
> > + "allwinner,sun4i-a10-gates-clk";
> > + reg = <0x01f01428 0x4>;
> > + #clock-cells = <1>;
> > + clocks = <&apb0>;
> > + clock-indices = <0>, <1>;
> > + clock-output-names = "apb0_pio", "apb0_ir";
> > + };
> > +
> > + ir_clk: ir_clk@01f01454 {
> > + compatible = "allwinner,sun4i-a10-mod0-clk";
> > + reg = <0x01f01454 0x4>;
> > + #clock-cells = <0>;
> > + clocks = <&osc32k>, <&osc24M>;
> > + clock-output-names = "ir";
> > + };
> > + };
> > +
> > + soc {
> > + compatible = "simple-bus";
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > + ranges;
> > +
> > + dma: dma-controller@01c02000 {
> > + compatible = "allwinner,sun8i-h3-dma";
> > + reg = <0x01c02000 0x1000>;
> > + interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_DMA>;
> > + resets = <&ccu RST_BUS_DMA>;
> > + #dma-cells = <1>;
> > + };
> > +
> > + mmc0: mmc@01c0f000 {
> > + /* compatible and clocks are in per SoC .dtsi file */
> > + reg = <0x01c0f000 0x1000>;
> > + resets = <&ccu RST_BUS_MMC0>;
> > + reset-names = "ahb";
> > + interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
> > + status = "disabled";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + };
> > +
> > + mmc1: mmc@01c10000 {
> > + /* compatible and clocks are in per SoC .dtsi file */
> > + reg = <0x01c10000 0x1000>;
> > + resets = <&ccu RST_BUS_MMC1>;
> > + reset-names = "ahb";
> > + interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
> > + status = "disabled";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + };
> > +
> > + mmc2: mmc@01c11000 {
> > + /* compatible and clocks are in per SoC .dtsi file */
> > + reg = <0x01c11000 0x1000>;
> > + resets = <&ccu RST_BUS_MMC2>;
> > + reset-names = "ahb";
> > + interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
> > + status = "disabled";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + };
> > +
> > + usbphy: phy@01c19400 {
> > + compatible = "allwinner,sun8i-h3-usb-phy";
> > + reg = <0x01c19400 0x2c>,
> > + <0x01c1a800 0x4>,
> > + <0x01c1b800 0x4>,
> > + <0x01c1c800 0x4>,
> > + <0x01c1d800 0x4>;
> > + reg-names = "phy_ctrl",
> > + "pmu0",
> > + "pmu1",
> > + "pmu2",
> > + "pmu3";
> > + clocks = <&ccu CLK_USB_PHY0>,
> > + <&ccu CLK_USB_PHY1>,
> > + <&ccu CLK_USB_PHY2>,
> > + <&ccu CLK_USB_PHY3>;
> > + clock-names = "usb0_phy",
> > + "usb1_phy",
> > + "usb2_phy",
> > + "usb3_phy";
> > + resets = <&ccu RST_USB_PHY0>,
> > + <&ccu RST_USB_PHY1>,
> > + <&ccu RST_USB_PHY2>,
> > + <&ccu RST_USB_PHY3>;
> > + reset-names = "usb0_reset",
> > + "usb1_reset",
> > + "usb2_reset",
> > + "usb3_reset";
> > + status = "disabled";
> > + #phy-cells = <1>;
> > + };
> > +
> > + ehci1: usb@01c1b000 {
> > + compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
> > + reg = <0x01c1b000 0x100>;
> > + interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>;
> > + resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
> > + phys = <&usbphy 1>;
> > + phy-names = "usb";
> > + status = "disabled";
> > + };
> > +
> > + ohci1: usb@01c1b400 {
> > + compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
> > + reg = <0x01c1b400 0x100>;
> > + interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>,
> > + <&ccu CLK_USB_OHCI1>;
> > + resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
> > + phys = <&usbphy 1>;
> > + phy-names = "usb";
> > + status = "disabled";
> > + };
> > +
> > + ehci2: usb@01c1c000 {
> > + compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
> > + reg = <0x01c1c000 0x100>;
> > + interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>;
> > + resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
> > + phys = <&usbphy 2>;
> > + phy-names = "usb";
> > + status = "disabled";
> > + };
> > +
> > + ohci2: usb@01c1c400 {
> > + compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
> > + reg = <0x01c1c400 0x100>;
> > + interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>,
> > + <&ccu CLK_USB_OHCI2>;
> > + resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
> > + phys = <&usbphy 2>;
> > + phy-names = "usb";
> > + status = "disabled";
> > + };
> > +
> > + ehci3: usb@01c1d000 {
> > + compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
> > + reg = <0x01c1d000 0x100>;
> > + interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>;
> > + resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
> > + phys = <&usbphy 3>;
> > + phy-names = "usb";
> > + status = "disabled";
> > + };
> > +
> > + ohci3: usb@01c1d400 {
> > + compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
> > + reg = <0x01c1d400 0x100>;
> > + interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>,
> > + <&ccu CLK_USB_OHCI3>;
> > + resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
> > + phys = <&usbphy 3>;
> > + phy-names = "usb";
> > + status = "disabled";
> > + };
> > +
> > + ccu: clock@01c20000 {
> > + /* compatible is in per SoC .dtsi file */
> > + reg = <0x01c20000 0x400>;
> > + clocks = <&osc24M>, <&osc32k>;
> > + clock-names = "hosc", "losc";
> > + #clock-cells = <1>;
> > + #reset-cells = <1>;
> > + };
> > +
> > + pio: pinctrl@01c20800 {
> > + /* compatible is in per SoC .dtsi file */
> > + reg = <0x01c20800 0x400>;
> > + interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
> > + <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
> > + clock-names = "apb", "hosc", "losc";
> > + gpio-controller;
> > + #gpio-cells = <3>;
> > + interrupt-controller;
> > + #interrupt-cells = <3>;
> > +
> > + i2c0_pins: i2c0 {
> > + pins = "PA11", "PA12";
> > + function = "i2c0";
> > + };
> > +
> > + i2c1_pins: i2c1 {
> > + pins = "PA18", "PA19";
> > + function = "i2c1";
> > + };
> > +
> > + i2c2_pins: i2c2 {
> > + pins = "PE12", "PE13";
> > + function = "i2c2";
> > + };
> > +
> > + mmc0_pins_a: mmc0@0 {
> > + pins = "PF0", "PF1", "PF2", "PF3",
> > + "PF4", "PF5";
> > + function = "mmc0";
> > + drive-strength = <30>;
> > + bias-pull-up;
> > + };
> > +
> > + mmc0_cd_pin: mmc0_cd_pin@0 {
> > + pins = "PF6";
> > + function = "gpio_in";
> > + bias-pull-up;
> > + };
> > +
> > + mmc1_pins_a: mmc1@0 {
> > + pins = "PG0", "PG1", "PG2", "PG3",
> > + "PG4", "PG5";
> > + function = "mmc1";
> > + drive-strength = <30>;
> > + bias-pull-up;
> > + };
> > +
> > + mmc2_8bit_pins: mmc2_8bit {
> > + pins = "PC5", "PC6", "PC8",
> > + "PC9", "PC10", "PC11",
> > + "PC12", "PC13", "PC14",
> > + "PC15", "PC16";
> > + function = "mmc2";
> > + drive-strength = <30>;
> > + bias-pull-up;
> > + };
> > +
> > + spi0_pins: spi0 {
> > + pins = "PC0", "PC1", "PC2", "PC3";
> > + function = "spi0";
> > + };
> > +
> > + spi1_pins: spi1 {
> > + pins = "PA15", "PA16", "PA14", "PA13";
> > + function = "spi1";
> > + };
> > +
> > + uart0_pins_a: uart0@0 {
> > + pins = "PA4", "PA5";
> > + function = "uart0";
> > + };
> > +
> > + uart1_pins: uart1 {
> > + pins = "PG6", "PG7";
> > + function = "uart1";
> > + };
> > +
> > + uart1_rts_cts_pins: uart1_rts_cts {
> > + pins = "PG8", "PG9";
> > + function = "uart1";
> > + };
> > +
> > + uart2_pins: uart2 {
> > + pins = "PA0", "PA1";
> > + function = "uart2";
> > + };
> > +
> > + uart3_pins: uart3 {
> > + pins = "PA13", "PA14";
> > + function = "uart3";
> > + };
> > + };
> > +
> > + timer@01c20c00 {
> > + compatible = "allwinner,sun4i-a10-timer";
> > + reg = <0x01c20c00 0xa0>;
> > + interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
> > + <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&osc24M>;
> > + };
> > +
> > + spi0: spi@01c68000 {
> > + compatible = "allwinner,sun8i-h3-spi";
> > + reg = <0x01c68000 0x1000>;
> > + interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
> > + clock-names = "ahb", "mod";
> > + dmas = <&dma 23>, <&dma 23>;
> > + dma-names = "rx", "tx";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&spi0_pins>;
> > + resets = <&ccu RST_BUS_SPI0>;
> > + status = "disabled";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + };
> > +
> > + spi1: spi@01c69000 {
> > + compatible = "allwinner,sun8i-h3-spi";
> > + reg = <0x01c69000 0x1000>;
> > + interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
> > + clock-names = "ahb", "mod";
> > + dmas = <&dma 24>, <&dma 24>;
> > + dma-names = "rx", "tx";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&spi1_pins>;
> > + resets = <&ccu RST_BUS_SPI1>;
> > + status = "disabled";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + };
> > +
> > + wdt0: watchdog@01c20ca0 {
> > + compatible = "allwinner,sun6i-a31-wdt";
> > + reg = <0x01c20ca0 0x20>;
> > + interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
> > + };
> > +
> > + pwm: pwm@01c21400 {
> > + compatible = "allwinner,sun8i-h3-pwm";
> > + reg = <0x01c21400 0x8>;
> > + clocks = <&osc24M>;
> > + #pwm-cells = <3>;
> > + status = "disabled";
> > + };
> > +
> > + codec: codec@01c22c00 {
> > + #sound-dai-cells = <0>;
> > + compatible = "allwinner,sun8i-h3-codec";
> > + reg = <0x01c22c00 0x400>;
> > + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
> > + clock-names = "apb", "codec";
> > + resets = <&ccu RST_BUS_CODEC>;
> > + dmas = <&dma 15>, <&dma 15>;
> > + dma-names = "rx", "tx";
> > + allwinner,codec-analog-controls = <&codec_analog>;
> > + status = "disabled";
> > + };
> > +
> > + uart0: serial@01c28000 {
> > + compatible = "snps,dw-apb-uart";
> > + reg = <0x01c28000 0x400>;
> > + interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
> > + reg-shift = <2>;
> > + reg-io-width = <4>;
> > + clocks = <&ccu CLK_BUS_UART0>;
> > + resets = <&ccu RST_BUS_UART0>;
> > + dmas = <&dma 6>, <&dma 6>;
> > + dma-names = "rx", "tx";
> > + status = "disabled";
> > + };
> > +
> > + uart1: serial@01c28400 {
> > + compatible = "snps,dw-apb-uart";
> > + reg = <0x01c28400 0x400>;
> > + interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
> > + reg-shift = <2>;
> > + reg-io-width = <4>;
> > + clocks = <&ccu CLK_BUS_UART1>;
> > + resets = <&ccu RST_BUS_UART1>;
> > + dmas = <&dma 7>, <&dma 7>;
> > + dma-names = "rx", "tx";
> > + status = "disabled";
> > + };
> > +
> > + uart2: serial@01c28800 {
> > + compatible = "snps,dw-apb-uart";
> > + reg = <0x01c28800 0x400>;
> > + interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
> > + reg-shift = <2>;
> > + reg-io-width = <4>;
> > + clocks = <&ccu CLK_BUS_UART2>;
> > + resets = <&ccu RST_BUS_UART2>;
> > + dmas = <&dma 8>, <&dma 8>;
> > + dma-names = "rx", "tx";
> > + status = "disabled";
> > + };
> > +
> > + uart3: serial@01c28c00 {
> > + compatible = "snps,dw-apb-uart";
> > + reg = <0x01c28c00 0x400>;
> > + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
> > + reg-shift = <2>;
> > + reg-io-width = <4>;
> > + clocks = <&ccu CLK_BUS_UART3>;
> > + resets = <&ccu RST_BUS_UART3>;
> > + dmas = <&dma 9>, <&dma 9>;
> > + dma-names = "rx", "tx";
> > + status = "disabled";
> > + };
> > +
> > + i2c0: i2c@01c2ac00 {
> > + compatible = "allwinner,sun6i-a31-i2c";
> > + reg = <0x01c2ac00 0x400>;
> > + interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_I2C0>;
> > + resets = <&ccu RST_BUS_I2C0>;
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&i2c0_pins>;
> > + status = "disabled";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + };
> > +
> > + i2c1: i2c@01c2b000 {
> > + compatible = "allwinner,sun6i-a31-i2c";
> > + reg = <0x01c2b000 0x400>;
> > + interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_I2C1>;
> > + resets = <&ccu RST_BUS_I2C1>;
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&i2c1_pins>;
> > + status = "disabled";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + };
> > +
> > + i2c2: i2c@01c2b400 {
> > + compatible = "allwinner,sun6i-a31-i2c";
> > + reg = <0x01c2b000 0x400>;
> > + interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&ccu CLK_BUS_I2C2>;
> > + resets = <&ccu RST_BUS_I2C2>;
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&i2c2_pins>;
> > + status = "disabled";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + };
> > +
> > + rtc: rtc@01f00000 {
> > + compatible = "allwinner,sun6i-a31-rtc";
> > + reg = <0x01f00000 0x54>;
> > + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
> > + <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
> > + };
> > +
> > + apb0_reset: reset@01f014b0 {
> > + reg = <0x01f014b0 0x4>;
> > + compatible = "allwinner,sun6i-a31-clock-reset";
> > + #reset-cells = <1>;
> > + };
> > +
> > + codec_analog: codec-analog@01f015c0 {
> > + compatible = "allwinner,sun8i-h3-codec-analog";
> > + reg = <0x01f015c0 0x4>;
> > + };
> > +
> > + ir: ir@01f02000 {
> > + compatible = "allwinner,sun5i-a13-ir";
> > + clocks = <&apb0_gates 1>, <&ir_clk>;
> > + clock-names = "apb", "ir";
> > + resets = <&apb0_reset 1>;
> > + interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> > + reg = <0x01f02000 0x40>;
> > + status = "disabled";
> > + };
> > +
> > + r_pio: pinctrl@01f02c00 {
> > + compatible = "allwinner,sun8i-h3-r-pinctrl";
> > + reg = <0x01f02c00 0x400>;
> > + interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&apb0_gates 0>, <&osc24M>, <&osc32k>;
> > + clock-names = "apb", "hosc", "losc";
> > + resets = <&apb0_reset 0>;
> > + gpio-controller;
> > + #gpio-cells = <3>;
> > + interrupt-controller;
> > + #interrupt-cells = <3>;
> > +
> > + ir_pins_a: ir@0 {
> > + pins = "PL11";
> > + function = "s_cir_rx";
> > + };
> > + };
> > + };
> > +};
> >
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe(a)googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
1
0