linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v2 0/7] AC97 device/driver model revamp
@ 2016-05-27 20:26 Robert Jarzmik
  2016-05-27 20:26 ` [RFC PATCH v2 1/7] ALSA: ac97: split out the generic ac97 registers Robert Jarzmik
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Robert Jarzmik @ 2016-05-27 20:26 UTC (permalink / raw)
  To: Robert Jarzmik, Daniel Mack, Haojian Zhuang, Jaroslav Kysela,
	Takashi Iwai, Liam Girdwood, Mark Brown
  Cc: linux-arm-kernel, linux-kernel, alsa-devel, patches

It all started in the pxa device-tree submission here :
   https://lkml.org/lkml/2016/2/25/965
   
It will be maintained in :
   git fetch https://github.com/rjarzmik/linux.git work/ac97

And now it transformed into this RFC, which would bring a ground for AC'97
devices closer to the linux device/driver model.

The driving ideas are still the same, and I put them in [1] for memory. This is
the second opus of the RFC. I'm intending to stop the RFC cycle here if possible
and have a true PATCH v1 submission after this RFC v2 unless there is a deep
design flaw uncovered.

I took into account Mark's and Takashi's remarks, I hope I forgot none. All the
changes should be documented in the first 2 patches mainly. I also added :
 - the AC97 link clock
   For now, bus code doesn't disable it in suspend and re-enable in resume,
   leaving the controller decide. I'm still pondering if for S2RAM (as opposed
   to runtime suspend), bus code should disable the clock.

 - the .h guards
   I'm not particularly happy with my naming even for v2, feel free to propose
   anything better, the codec.h is particularly ugly.

 - statics and namespace pollution
   I made more functions static, limiting further the namespace pollution.

 - Kconfig/Makefile layout change
   I get the feeling that the KConfig "select" flavor would have better been a
   "depends on" one. And yet I didn't find a good way to enforce it, because of
   the way sound/soc/codecs/Kconfig is designed, and I'm afraid to break the
   structure by doing a "depends on AC97_BUS_NEW" in WM9713 configuration.

Let's have another review cycle, that will let me test this serie more
thoroughly, especially the suspend/resume and the reset in the resume, which
doesn't work, and requires me to test more deeply. I'll also test by removing
the wm9713 change to see how robust the implementation is.

Happy review.

--
Robert

Robert Jarzmik (7):
  ALSA: ac97: split out the generic ac97 registers
  ALSA: ac97: add an ac97 bus
  ASoC: add new ac97 bus support
  ASoC: wm9713: add ac97 new bus support
  ASoC: pxa: switch to new ac97 bus support
  ARM: pxa: mioa701 convert to the new AC97 bus
  ASoC: mioa701_wm9713: convert to new ac97 bus

 arch/arm/mach-pxa/mioa701.c     |  12 +-
 include/sound/ac97/codec.h      | 111 ++++++++++++
 include/sound/ac97/compat.h     |  21 +++
 include/sound/ac97/controller.h |  80 +++++++++
 include/sound/ac97/regs.h       | 262 +++++++++++++++++++++++++++
 include/sound/ac97_codec.h      | 239 +------------------------
 include/sound/pxa2xx-lib.h      |  15 +-
 sound/Kconfig                   |   2 +
 sound/Makefile                  |   1 +
 sound/ac97/Kconfig              |  18 ++
 sound/ac97/Makefile             |   8 +
 sound/ac97/ac97_core.h          |  10 ++
 sound/ac97/bus.c                | 381 ++++++++++++++++++++++++++++++++++++++++
 sound/ac97/codec.c              |  15 ++
 sound/ac97/snd_ac97_compat.c    | 104 +++++++++++
 sound/arm/Kconfig               |   1 -
 sound/arm/pxa2xx-ac97-lib.c     |  39 ++--
 sound/soc/Kconfig               |   4 +
 sound/soc/codecs/Kconfig        |   1 +
 sound/soc/codecs/wm9713.c       |  62 ++++++-
 sound/soc/pxa/Kconfig           |   4 +-
 sound/soc/pxa/mioa701_wm9713.c  |   4 +-
 sound/soc/pxa/pxa2xx-ac97.c     |  20 ++-
 23 files changed, 1132 insertions(+), 282 deletions(-)
 create mode 100644 include/sound/ac97/codec.h
 create mode 100644 include/sound/ac97/compat.h
 create mode 100644 include/sound/ac97/controller.h
 create mode 100644 include/sound/ac97/regs.h
 create mode 100644 sound/ac97/Kconfig
 create mode 100644 sound/ac97/Makefile
 create mode 100644 sound/ac97/ac97_core.h
 create mode 100644 sound/ac97/bus.c
 create mode 100644 sound/ac97/codec.c
 create mode 100644 sound/ac97/snd_ac97_compat.c

-- 
2.1.4

[1] RFC PATCH reminder:

Amongst the driving ideas behind this RFC :
 - use device/driver model for AC'97
   device/driver binding is based on vendor_id{1,2}
 - use auto-probe of the AC'97 bus to enumerate codecs and create devices
 - be compatible with previous platform_data model for codecs
   => this enables a smooth transition, where a codec (here wm9713) can
      be used either through platform_device or automatic discovery
 - struct snd_ac97 is not used
   This structure is really heavy, and doesn't represent an AC97 device, but
   rather an AC'97 codec internals IIUC.
   I think it's right place would be in include/sound/ac97/codec.h.
   This is also a problem for regmap adherence, hence the
   include/sound/ac97/compat.h.
 - a new AC'97 bus Kconfig is created
   This was done for a smooth transition ... let's see if it's a good idea.
 - split the AC'97 into :
   - the codec
   - the digital controller
   - the bus

Amongst the things that are not all touched yet :
 - ac97_codec.c
   The generic AC'97 codec in sound/pci/ac97/ac97_codec.c has really a lot
   features, which are not at all PCI related. They could be transfered to
   sound/ac97, without the pci specific field.
   => this deserves a deep ahead thinking, which I'll do if the current approach
   is accepted by the communauty.

The most important patch is 2/7 "ALSA: ac97: add an ac97 bus". This is the main
evaluation point for the serie, the others are here so that I can test it all.

Well, this is a long term effort, which might need a complete rewrite according
to the comments it'll get. Let's expose it for comments and see how I can
progress with it.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 1/7] ALSA: ac97: split out the generic ac97 registers
  2016-05-27 20:26 [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
@ 2016-05-27 20:26 ` Robert Jarzmik
  2016-05-27 20:26 ` [RFC PATCH v2 2/7] ALSA: ac97: add an ac97 bus Robert Jarzmik
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Robert Jarzmik @ 2016-05-27 20:26 UTC (permalink / raw)
  To: Robert Jarzmik, Daniel Mack, Haojian Zhuang, Jaroslav Kysela,
	Takashi Iwai, Liam Girdwood, Mark Brown
  Cc: linux-arm-kernel, linux-kernel, alsa-devel, patches

Split out from the ac97_codec.h the ac97 generic registers, which can be
used by a codec, typically a generic ac97 codec, and by the ac97 bus, to
scan an ac97 AC-Link.

This split encompasses all the AC97 standard registers, but not the
codec specific ones.

In order to have a clean split between former ac97 bus implementation
and the new coming one in sound/ac97, it is safer to not include any
former ac97 includes, excepting in sound/ac97/compat.c.

Amongst the thing to isolate :
 - don't have the struct snd_ac97 in sound/ac97/* (except compat.c) to not
   be "fooled" by a definition which would come with ac97_codec.h by
   "chance".
 - don't have to have snd_a97_*() functions, as they rely on struct snd_ac97.
 - don't want the struct snd_ac97_bus_ops, there is a new one

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
Since v1: improve commit message to explain better the rationale
---
 include/sound/ac97/regs.h  | 262 +++++++++++++++++++++++++++++++++++++++++++++
 include/sound/ac97_codec.h | 239 +----------------------------------------
 2 files changed, 263 insertions(+), 238 deletions(-)
 create mode 100644 include/sound/ac97/regs.h

diff --git a/include/sound/ac97/regs.h b/include/sound/ac97/regs.h
new file mode 100644
index 000000000000..4bb86d379bd5
--- /dev/null
+++ b/include/sound/ac97/regs.h
@@ -0,0 +1,262 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *  Universal interface for Audio Codec '97
+ *
+ *  For more details look to AC '97 component specification revision 2.1
+ *  by Intel Corporation (http://developer.intel.com).
+ *
+ *
+ *   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.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+/*
+ *  AC'97 codec registers
+ */
+
+#define AC97_RESET		0x00	/* Reset */
+#define AC97_MASTER		0x02	/* Master Volume */
+#define AC97_HEADPHONE		0x04	/* Headphone Volume (optional) */
+#define AC97_MASTER_MONO	0x06	/* Master Volume Mono (optional) */
+#define AC97_MASTER_TONE	0x08	/* Master Tone (Bass & Treble) (optional) */
+#define AC97_PC_BEEP		0x0a	/* PC Beep Volume (optinal) */
+#define AC97_PHONE		0x0c	/* Phone Volume (optional) */
+#define AC97_MIC		0x0e	/* MIC Volume */
+#define AC97_LINE		0x10	/* Line In Volume */
+#define AC97_CD			0x12	/* CD Volume */
+#define AC97_VIDEO		0x14	/* Video Volume (optional) */
+#define AC97_AUX		0x16	/* AUX Volume (optional) */
+#define AC97_PCM		0x18	/* PCM Volume */
+#define AC97_REC_SEL		0x1a	/* Record Select */
+#define AC97_REC_GAIN		0x1c	/* Record Gain */
+#define AC97_REC_GAIN_MIC	0x1e	/* Record Gain MIC (optional) */
+#define AC97_GENERAL_PURPOSE	0x20	/* General Purpose (optional) */
+#define AC97_3D_CONTROL		0x22	/* 3D Control (optional) */
+#define AC97_INT_PAGING		0x24	/* Audio Interrupt & Paging (AC'97 2.3) */
+#define AC97_POWERDOWN		0x26	/* Powerdown control / status */
+/* range 0x28-0x3a - AUDIO AC'97 2.0 extensions */
+#define AC97_EXTENDED_ID	0x28	/* Extended Audio ID */
+#define AC97_EXTENDED_STATUS	0x2a	/* Extended Audio Status and Control */
+#define AC97_PCM_FRONT_DAC_RATE 0x2c	/* PCM Front DAC Rate */
+#define AC97_PCM_SURR_DAC_RATE	0x2e	/* PCM Surround DAC Rate */
+#define AC97_PCM_LFE_DAC_RATE	0x30	/* PCM LFE DAC Rate */
+#define AC97_PCM_LR_ADC_RATE	0x32	/* PCM LR ADC Rate */
+#define AC97_PCM_MIC_ADC_RATE	0x34	/* PCM MIC ADC Rate */
+#define AC97_CENTER_LFE_MASTER	0x36	/* Center + LFE Master Volume */
+#define AC97_SURROUND_MASTER	0x38	/* Surround (Rear) Master Volume */
+#define AC97_SPDIF		0x3a	/* S/PDIF control */
+/* range 0x3c-0x58 - MODEM */
+#define AC97_EXTENDED_MID	0x3c	/* Extended Modem ID */
+#define AC97_EXTENDED_MSTATUS	0x3e	/* Extended Modem Status and Control */
+#define AC97_LINE1_RATE		0x40	/* Line1 DAC/ADC Rate */
+#define AC97_LINE2_RATE		0x42	/* Line2 DAC/ADC Rate */
+#define AC97_HANDSET_RATE	0x44	/* Handset DAC/ADC Rate */
+#define AC97_LINE1_LEVEL	0x46	/* Line1 DAC/ADC Level */
+#define AC97_LINE2_LEVEL	0x48	/* Line2 DAC/ADC Level */
+#define AC97_HANDSET_LEVEL	0x4a	/* Handset DAC/ADC Level */
+#define AC97_GPIO_CFG		0x4c	/* GPIO Configuration */
+#define AC97_GPIO_POLARITY	0x4e	/* GPIO Pin Polarity/Type, 0=low, 1=high active */
+#define AC97_GPIO_STICKY	0x50	/* GPIO Pin Sticky, 0=not, 1=sticky */
+#define AC97_GPIO_WAKEUP	0x52	/* GPIO Pin Wakeup, 0=no int, 1=yes int */
+#define AC97_GPIO_STATUS	0x54	/* GPIO Pin Status, slot 12 */
+#define AC97_MISC_AFE		0x56	/* Miscellaneous Modem AFE Status and Control */
+/* range 0x5a-0x7b - Vendor Specific */
+#define AC97_VENDOR_ID1		0x7c	/* Vendor ID1 */
+#define AC97_VENDOR_ID2		0x7e	/* Vendor ID2 / revision */
+/* range 0x60-0x6f (page 1) - extended codec registers */
+#define AC97_CODEC_CLASS_REV	0x60	/* Codec Class/Revision */
+#define AC97_PCI_SVID		0x62	/* PCI Subsystem Vendor ID */
+#define AC97_PCI_SID		0x64	/* PCI Subsystem ID */
+#define AC97_FUNC_SELECT	0x66	/* Function Select */
+#define AC97_FUNC_INFO		0x68	/* Function Information */
+#define AC97_SENSE_INFO		0x6a	/* Sense Details */
+
+/* volume controls */
+#define AC97_MUTE_MASK_MONO	0x8000
+#define AC97_MUTE_MASK_STEREO	0x8080
+
+/* slot allocation */
+#define AC97_SLOT_TAG		0
+#define AC97_SLOT_CMD_ADDR	1
+#define AC97_SLOT_CMD_DATA	2
+#define AC97_SLOT_PCM_LEFT	3
+#define AC97_SLOT_PCM_RIGHT	4
+#define AC97_SLOT_MODEM_LINE1	5
+#define AC97_SLOT_PCM_CENTER	6
+#define AC97_SLOT_MIC		6	/* input */
+#define AC97_SLOT_SPDIF_LEFT1	6
+#define AC97_SLOT_PCM_SLEFT	7	/* surround left */
+#define AC97_SLOT_PCM_LEFT_0	7	/* double rate operation */
+#define AC97_SLOT_SPDIF_LEFT	7
+#define AC97_SLOT_PCM_SRIGHT	8	/* surround right */
+#define AC97_SLOT_PCM_RIGHT_0	8	/* double rate operation */
+#define AC97_SLOT_SPDIF_RIGHT	8
+#define AC97_SLOT_LFE		9
+#define AC97_SLOT_SPDIF_RIGHT1	9
+#define AC97_SLOT_MODEM_LINE2	10
+#define AC97_SLOT_PCM_LEFT_1	10	/* double rate operation */
+#define AC97_SLOT_SPDIF_LEFT2	10
+#define AC97_SLOT_HANDSET	11	/* output */
+#define AC97_SLOT_PCM_RIGHT_1	11	/* double rate operation */
+#define AC97_SLOT_SPDIF_RIGHT2	11
+#define AC97_SLOT_MODEM_GPIO	12	/* modem GPIO */
+#define AC97_SLOT_PCM_CENTER_1	12	/* double rate operation */
+
+/* basic capabilities (reset register) */
+#define AC97_BC_DEDICATED_MIC	0x0001	/* Dedicated Mic PCM In Channel */
+#define AC97_BC_RESERVED1	0x0002	/* Reserved (was Modem Line Codec support) */
+#define AC97_BC_BASS_TREBLE	0x0004	/* Bass & Treble Control */
+#define AC97_BC_SIM_STEREO	0x0008	/* Simulated stereo */
+#define AC97_BC_HEADPHONE	0x0010	/* Headphone Out Support */
+#define AC97_BC_LOUDNESS	0x0020	/* Loudness (bass boost) Support */
+#define AC97_BC_16BIT_DAC	0x0000	/* 16-bit DAC resolution */
+#define AC97_BC_18BIT_DAC	0x0040	/* 18-bit DAC resolution */
+#define AC97_BC_20BIT_DAC	0x0080	/* 20-bit DAC resolution */
+#define AC97_BC_DAC_MASK	0x00c0
+#define AC97_BC_16BIT_ADC	0x0000	/* 16-bit ADC resolution */
+#define AC97_BC_18BIT_ADC	0x0100	/* 18-bit ADC resolution */
+#define AC97_BC_20BIT_ADC	0x0200	/* 20-bit ADC resolution */
+#define AC97_BC_ADC_MASK	0x0300
+#define AC97_BC_3D_TECH_ID_MASK	0x7c00	/* Per-vendor ID of 3D enhancement */
+
+/* general purpose */
+#define AC97_GP_DRSS_MASK	0x0c00	/* double rate slot select */
+#define AC97_GP_DRSS_1011	0x0000	/* LR(C) 10+11(+12) */
+#define AC97_GP_DRSS_78		0x0400	/* LR 7+8 */
+
+/* powerdown bits */
+#define AC97_PD_ADC_STATUS	0x0001	/* ADC status (RO) */
+#define AC97_PD_DAC_STATUS	0x0002	/* DAC status (RO) */
+#define AC97_PD_MIXER_STATUS	0x0004	/* Analog mixer status (RO) */
+#define AC97_PD_VREF_STATUS	0x0008	/* Vref status (RO) */
+#define AC97_PD_PR0		0x0100	/* Power down PCM ADCs and input MUX */
+#define AC97_PD_PR1		0x0200	/* Power down PCM front DAC */
+#define AC97_PD_PR2		0x0400	/* Power down Mixer (Vref still on) */
+#define AC97_PD_PR3		0x0800	/* Power down Mixer (Vref off) */
+#define AC97_PD_PR4		0x1000	/* Power down AC-Link */
+#define AC97_PD_PR5		0x2000	/* Disable internal clock usage */
+#define AC97_PD_PR6		0x4000	/* Headphone amplifier */
+#define AC97_PD_EAPD		0x8000	/* External Amplifer Power Down (EAPD) */
+
+/* extended audio ID bit defines */
+#define AC97_EI_VRA		0x0001	/* Variable bit rate supported */
+#define AC97_EI_DRA		0x0002	/* Double rate supported */
+#define AC97_EI_SPDIF		0x0004	/* S/PDIF out supported */
+#define AC97_EI_VRM		0x0008	/* Variable bit rate supported for MIC */
+#define AC97_EI_DACS_SLOT_MASK	0x0030	/* DACs slot assignment */
+#define AC97_EI_DACS_SLOT_SHIFT	4
+#define AC97_EI_CDAC		0x0040	/* PCM Center DAC available */
+#define AC97_EI_SDAC		0x0080	/* PCM Surround DACs available */
+#define AC97_EI_LDAC		0x0100	/* PCM LFE DAC available */
+#define AC97_EI_AMAP		0x0200	/* indicates optional slot/DAC mapping based on codec ID */
+#define AC97_EI_REV_MASK	0x0c00	/* AC'97 revision mask */
+#define AC97_EI_REV_22		0x0400	/* AC'97 revision 2.2 */
+#define AC97_EI_REV_23		0x0800	/* AC'97 revision 2.3 */
+#define AC97_EI_REV_SHIFT	10
+#define AC97_EI_ADDR_MASK	0xc000	/* physical codec ID (address) */
+#define AC97_EI_ADDR_SHIFT	14
+
+/* extended audio status and control bit defines */
+#define AC97_EA_VRA		0x0001	/* Variable bit rate enable bit */
+#define AC97_EA_DRA		0x0002	/* Double-rate audio enable bit */
+#define AC97_EA_SPDIF		0x0004	/* S/PDIF out enable bit */
+#define AC97_EA_VRM		0x0008	/* Variable bit rate for MIC enable bit */
+#define AC97_EA_SPSA_SLOT_MASK	0x0030	/* Mask for slot assignment bits */
+#define AC97_EA_SPSA_SLOT_SHIFT 4
+#define AC97_EA_SPSA_3_4	0x0000	/* Slot assigned to 3 & 4 */
+#define AC97_EA_SPSA_7_8	0x0010	/* Slot assigned to 7 & 8 */
+#define AC97_EA_SPSA_6_9	0x0020	/* Slot assigned to 6 & 9 */
+#define AC97_EA_SPSA_10_11	0x0030	/* Slot assigned to 10 & 11 */
+#define AC97_EA_CDAC		0x0040	/* PCM Center DAC is ready (Read only) */
+#define AC97_EA_SDAC		0x0080	/* PCM Surround DACs are ready (Read only) */
+#define AC97_EA_LDAC		0x0100	/* PCM LFE DAC is ready (Read only) */
+#define AC97_EA_MDAC		0x0200	/* MIC ADC is ready (Read only) */
+#define AC97_EA_SPCV		0x0400	/* S/PDIF configuration valid (Read only) */
+#define AC97_EA_PRI		0x0800	/* Turns the PCM Center DAC off */
+#define AC97_EA_PRJ		0x1000	/* Turns the PCM Surround DACs off */
+#define AC97_EA_PRK		0x2000	/* Turns the PCM LFE DAC off */
+#define AC97_EA_PRL		0x4000	/* Turns the MIC ADC off */
+
+/* S/PDIF control bit defines */
+#define AC97_SC_PRO		0x0001	/* Professional status */
+#define AC97_SC_NAUDIO		0x0002	/* Non audio stream */
+#define AC97_SC_COPY		0x0004	/* Copyright status */
+#define AC97_SC_PRE		0x0008	/* Preemphasis status */
+#define AC97_SC_CC_MASK		0x07f0	/* Category Code mask */
+#define AC97_SC_CC_SHIFT	4
+#define AC97_SC_L		0x0800	/* Generation Level status */
+#define AC97_SC_SPSR_MASK	0x3000	/* S/PDIF Sample Rate bits */
+#define AC97_SC_SPSR_SHIFT	12
+#define AC97_SC_SPSR_44K	0x0000	/* Use 44.1kHz Sample rate */
+#define AC97_SC_SPSR_48K	0x2000	/* Use 48kHz Sample rate */
+#define AC97_SC_SPSR_32K	0x3000	/* Use 32kHz Sample rate */
+#define AC97_SC_DRS		0x4000	/* Double Rate S/PDIF */
+#define AC97_SC_V		0x8000	/* Validity status */
+
+/* Interrupt and Paging bit defines (AC'97 2.3) */
+#define AC97_PAGE_MASK		0x000f	/* Page Selector */
+#define AC97_PAGE_VENDOR	0	/* Vendor-specific registers */
+#define AC97_PAGE_1		1	/* Extended Codec Registers page 1 */
+#define AC97_INT_ENABLE		0x0800	/* Interrupt Enable */
+#define AC97_INT_SENSE		0x1000	/* Sense Cycle */
+#define AC97_INT_CAUSE_SENSE	0x2000	/* Sense Cycle Completed (RO) */
+#define AC97_INT_CAUSE_GPIO	0x4000	/* GPIO bits changed (RO) */
+#define AC97_INT_STATUS		0x8000	/* Interrupt Status */
+
+/* extended modem ID bit defines */
+#define AC97_MEI_LINE1		0x0001	/* Line1 present */
+#define AC97_MEI_LINE2		0x0002	/* Line2 present */
+#define AC97_MEI_HANDSET	0x0004	/* Handset present */
+#define AC97_MEI_CID1		0x0008	/* caller ID decode for Line1 is supported */
+#define AC97_MEI_CID2		0x0010	/* caller ID decode for Line2 is supported */
+#define AC97_MEI_ADDR_MASK	0xc000	/* physical codec ID (address) */
+#define AC97_MEI_ADDR_SHIFT	14
+
+/* extended modem status and control bit defines */
+#define AC97_MEA_GPIO		0x0001	/* GPIO is ready (ro) */
+#define AC97_MEA_MREF		0x0002	/* Vref is up to nominal level (ro) */
+#define AC97_MEA_ADC1		0x0004	/* ADC1 operational (ro) */
+#define AC97_MEA_DAC1		0x0008	/* DAC1 operational (ro) */
+#define AC97_MEA_ADC2		0x0010	/* ADC2 operational (ro) */
+#define AC97_MEA_DAC2		0x0020	/* DAC2 operational (ro) */
+#define AC97_MEA_HADC		0x0040	/* HADC operational (ro) */
+#define AC97_MEA_HDAC		0x0080	/* HDAC operational (ro) */
+#define AC97_MEA_PRA		0x0100	/* GPIO power down (high) */
+#define AC97_MEA_PRB		0x0200	/* reserved */
+#define AC97_MEA_PRC		0x0400	/* ADC1 power down (high) */
+#define AC97_MEA_PRD		0x0800	/* DAC1 power down (high) */
+#define AC97_MEA_PRE		0x1000	/* ADC2 power down (high) */
+#define AC97_MEA_PRF		0x2000	/* DAC2 power down (high) */
+#define AC97_MEA_PRG		0x4000	/* HADC power down (high) */
+#define AC97_MEA_PRH		0x8000	/* HDAC power down (high) */
+
+/* modem gpio status defines */
+#define AC97_GPIO_LINE1_OH      0x0001  /* Off Hook Line1 */
+#define AC97_GPIO_LINE1_RI      0x0002  /* Ring Detect Line1 */
+#define AC97_GPIO_LINE1_CID     0x0004  /* Caller ID path enable Line1 */
+#define AC97_GPIO_LINE1_LCS     0x0008  /* Loop Current Sense Line1 */
+#define AC97_GPIO_LINE1_PULSE   0x0010  /* Opt./ Pulse Dial Line1 (out) */
+#define AC97_GPIO_LINE1_HL1R    0x0020  /* Opt./ Handset to Line1 relay control (out) */
+#define AC97_GPIO_LINE1_HOHD    0x0040  /* Opt./ Handset off hook detect Line1 (in) */
+#define AC97_GPIO_LINE12_AC     0x0080  /* Opt./ Int.bit 1 / Line1/2 AC (out) */
+#define AC97_GPIO_LINE12_DC     0x0100  /* Opt./ Int.bit 2 / Line1/2 DC (out) */
+#define AC97_GPIO_LINE12_RS     0x0200  /* Opt./ Int.bit 3 / Line1/2 RS (out) */
+#define AC97_GPIO_LINE2_OH      0x0400  /* Off Hook Line2 */
+#define AC97_GPIO_LINE2_RI      0x0800  /* Ring Detect Line2 */
+#define AC97_GPIO_LINE2_CID     0x1000  /* Caller ID path enable Line2 */
+#define AC97_GPIO_LINE2_LCS     0x2000  /* Loop Current Sense Line2 */
+#define AC97_GPIO_LINE2_PULSE   0x4000  /* Opt./ Pulse Dial Line2 (out) */
+#define AC97_GPIO_LINE2_HL1R    0x8000  /* Opt./ Handset to Line2 relay control (out) */
+
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 15aa5f07c955..89d311a503d3 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -28,6 +28,7 @@
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/workqueue.h>
+#include <sound/ac97/regs.h>
 #include <sound/pcm.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -35,244 +36,6 @@
 /* maximum number of devices on the AC97 bus */
 #define	AC97_BUS_MAX_DEVICES	4
 
-/*
- *  AC'97 codec registers
- */
-
-#define AC97_RESET		0x00	/* Reset */
-#define AC97_MASTER		0x02	/* Master Volume */
-#define AC97_HEADPHONE		0x04	/* Headphone Volume (optional) */
-#define AC97_MASTER_MONO	0x06	/* Master Volume Mono (optional) */
-#define AC97_MASTER_TONE	0x08	/* Master Tone (Bass & Treble) (optional) */
-#define AC97_PC_BEEP		0x0a	/* PC Beep Volume (optinal) */
-#define AC97_PHONE		0x0c	/* Phone Volume (optional) */
-#define AC97_MIC		0x0e	/* MIC Volume */
-#define AC97_LINE		0x10	/* Line In Volume */
-#define AC97_CD			0x12	/* CD Volume */
-#define AC97_VIDEO		0x14	/* Video Volume (optional) */
-#define AC97_AUX		0x16	/* AUX Volume (optional) */
-#define AC97_PCM		0x18	/* PCM Volume */
-#define AC97_REC_SEL		0x1a	/* Record Select */
-#define AC97_REC_GAIN		0x1c	/* Record Gain */
-#define AC97_REC_GAIN_MIC	0x1e	/* Record Gain MIC (optional) */
-#define AC97_GENERAL_PURPOSE	0x20	/* General Purpose (optional) */
-#define AC97_3D_CONTROL		0x22	/* 3D Control (optional) */
-#define AC97_INT_PAGING		0x24	/* Audio Interrupt & Paging (AC'97 2.3) */
-#define AC97_POWERDOWN		0x26	/* Powerdown control / status */
-/* range 0x28-0x3a - AUDIO AC'97 2.0 extensions */
-#define AC97_EXTENDED_ID	0x28	/* Extended Audio ID */
-#define AC97_EXTENDED_STATUS	0x2a	/* Extended Audio Status and Control */
-#define AC97_PCM_FRONT_DAC_RATE 0x2c	/* PCM Front DAC Rate */
-#define AC97_PCM_SURR_DAC_RATE	0x2e	/* PCM Surround DAC Rate */
-#define AC97_PCM_LFE_DAC_RATE	0x30	/* PCM LFE DAC Rate */
-#define AC97_PCM_LR_ADC_RATE	0x32	/* PCM LR ADC Rate */
-#define AC97_PCM_MIC_ADC_RATE	0x34	/* PCM MIC ADC Rate */
-#define AC97_CENTER_LFE_MASTER	0x36	/* Center + LFE Master Volume */
-#define AC97_SURROUND_MASTER	0x38	/* Surround (Rear) Master Volume */
-#define AC97_SPDIF		0x3a	/* S/PDIF control */
-/* range 0x3c-0x58 - MODEM */
-#define AC97_EXTENDED_MID	0x3c	/* Extended Modem ID */
-#define AC97_EXTENDED_MSTATUS	0x3e	/* Extended Modem Status and Control */
-#define AC97_LINE1_RATE		0x40	/* Line1 DAC/ADC Rate */
-#define AC97_LINE2_RATE		0x42	/* Line2 DAC/ADC Rate */
-#define AC97_HANDSET_RATE	0x44	/* Handset DAC/ADC Rate */
-#define AC97_LINE1_LEVEL	0x46	/* Line1 DAC/ADC Level */
-#define AC97_LINE2_LEVEL	0x48	/* Line2 DAC/ADC Level */
-#define AC97_HANDSET_LEVEL	0x4a	/* Handset DAC/ADC Level */
-#define AC97_GPIO_CFG		0x4c	/* GPIO Configuration */
-#define AC97_GPIO_POLARITY	0x4e	/* GPIO Pin Polarity/Type, 0=low, 1=high active */
-#define AC97_GPIO_STICKY	0x50	/* GPIO Pin Sticky, 0=not, 1=sticky */
-#define AC97_GPIO_WAKEUP	0x52	/* GPIO Pin Wakeup, 0=no int, 1=yes int */
-#define AC97_GPIO_STATUS	0x54	/* GPIO Pin Status, slot 12 */
-#define AC97_MISC_AFE		0x56	/* Miscellaneous Modem AFE Status and Control */
-/* range 0x5a-0x7b - Vendor Specific */
-#define AC97_VENDOR_ID1		0x7c	/* Vendor ID1 */
-#define AC97_VENDOR_ID2		0x7e	/* Vendor ID2 / revision */
-/* range 0x60-0x6f (page 1) - extended codec registers */
-#define AC97_CODEC_CLASS_REV	0x60	/* Codec Class/Revision */
-#define AC97_PCI_SVID		0x62	/* PCI Subsystem Vendor ID */
-#define AC97_PCI_SID		0x64	/* PCI Subsystem ID */
-#define AC97_FUNC_SELECT	0x66	/* Function Select */
-#define AC97_FUNC_INFO		0x68	/* Function Information */
-#define AC97_SENSE_INFO		0x6a	/* Sense Details */
-
-/* volume controls */
-#define AC97_MUTE_MASK_MONO	0x8000
-#define AC97_MUTE_MASK_STEREO	0x8080
-
-/* slot allocation */
-#define AC97_SLOT_TAG		0
-#define AC97_SLOT_CMD_ADDR	1
-#define AC97_SLOT_CMD_DATA	2
-#define AC97_SLOT_PCM_LEFT	3
-#define AC97_SLOT_PCM_RIGHT	4
-#define AC97_SLOT_MODEM_LINE1	5
-#define AC97_SLOT_PCM_CENTER	6
-#define AC97_SLOT_MIC		6	/* input */
-#define AC97_SLOT_SPDIF_LEFT1	6
-#define AC97_SLOT_PCM_SLEFT	7	/* surround left */
-#define AC97_SLOT_PCM_LEFT_0	7	/* double rate operation */
-#define AC97_SLOT_SPDIF_LEFT	7
-#define AC97_SLOT_PCM_SRIGHT	8	/* surround right */
-#define AC97_SLOT_PCM_RIGHT_0	8	/* double rate operation */
-#define AC97_SLOT_SPDIF_RIGHT	8
-#define AC97_SLOT_LFE		9
-#define AC97_SLOT_SPDIF_RIGHT1	9
-#define AC97_SLOT_MODEM_LINE2	10
-#define AC97_SLOT_PCM_LEFT_1	10	/* double rate operation */
-#define AC97_SLOT_SPDIF_LEFT2	10
-#define AC97_SLOT_HANDSET	11	/* output */
-#define AC97_SLOT_PCM_RIGHT_1	11	/* double rate operation */
-#define AC97_SLOT_SPDIF_RIGHT2	11
-#define AC97_SLOT_MODEM_GPIO	12	/* modem GPIO */
-#define AC97_SLOT_PCM_CENTER_1	12	/* double rate operation */
-
-/* basic capabilities (reset register) */
-#define AC97_BC_DEDICATED_MIC	0x0001	/* Dedicated Mic PCM In Channel */
-#define AC97_BC_RESERVED1	0x0002	/* Reserved (was Modem Line Codec support) */
-#define AC97_BC_BASS_TREBLE	0x0004	/* Bass & Treble Control */
-#define AC97_BC_SIM_STEREO	0x0008	/* Simulated stereo */
-#define AC97_BC_HEADPHONE	0x0010	/* Headphone Out Support */
-#define AC97_BC_LOUDNESS	0x0020	/* Loudness (bass boost) Support */
-#define AC97_BC_16BIT_DAC	0x0000	/* 16-bit DAC resolution */
-#define AC97_BC_18BIT_DAC	0x0040	/* 18-bit DAC resolution */
-#define AC97_BC_20BIT_DAC	0x0080	/* 20-bit DAC resolution */
-#define AC97_BC_DAC_MASK	0x00c0
-#define AC97_BC_16BIT_ADC	0x0000	/* 16-bit ADC resolution */
-#define AC97_BC_18BIT_ADC	0x0100	/* 18-bit ADC resolution */
-#define AC97_BC_20BIT_ADC	0x0200	/* 20-bit ADC resolution */
-#define AC97_BC_ADC_MASK	0x0300
-#define AC97_BC_3D_TECH_ID_MASK	0x7c00	/* Per-vendor ID of 3D enhancement */
-
-/* general purpose */
-#define AC97_GP_DRSS_MASK	0x0c00	/* double rate slot select */
-#define AC97_GP_DRSS_1011	0x0000	/* LR(C) 10+11(+12) */
-#define AC97_GP_DRSS_78		0x0400	/* LR 7+8 */
-
-/* powerdown bits */
-#define AC97_PD_ADC_STATUS	0x0001	/* ADC status (RO) */
-#define AC97_PD_DAC_STATUS	0x0002	/* DAC status (RO) */
-#define AC97_PD_MIXER_STATUS	0x0004	/* Analog mixer status (RO) */
-#define AC97_PD_VREF_STATUS	0x0008	/* Vref status (RO) */
-#define AC97_PD_PR0		0x0100	/* Power down PCM ADCs and input MUX */
-#define AC97_PD_PR1		0x0200	/* Power down PCM front DAC */
-#define AC97_PD_PR2		0x0400	/* Power down Mixer (Vref still on) */
-#define AC97_PD_PR3		0x0800	/* Power down Mixer (Vref off) */
-#define AC97_PD_PR4		0x1000	/* Power down AC-Link */
-#define AC97_PD_PR5		0x2000	/* Disable internal clock usage */
-#define AC97_PD_PR6		0x4000	/* Headphone amplifier */
-#define AC97_PD_EAPD		0x8000	/* External Amplifer Power Down (EAPD) */
-
-/* extended audio ID bit defines */
-#define AC97_EI_VRA		0x0001	/* Variable bit rate supported */
-#define AC97_EI_DRA		0x0002	/* Double rate supported */
-#define AC97_EI_SPDIF		0x0004	/* S/PDIF out supported */
-#define AC97_EI_VRM		0x0008	/* Variable bit rate supported for MIC */
-#define AC97_EI_DACS_SLOT_MASK	0x0030	/* DACs slot assignment */
-#define AC97_EI_DACS_SLOT_SHIFT	4
-#define AC97_EI_CDAC		0x0040	/* PCM Center DAC available */
-#define AC97_EI_SDAC		0x0080	/* PCM Surround DACs available */
-#define AC97_EI_LDAC		0x0100	/* PCM LFE DAC available */
-#define AC97_EI_AMAP		0x0200	/* indicates optional slot/DAC mapping based on codec ID */
-#define AC97_EI_REV_MASK	0x0c00	/* AC'97 revision mask */
-#define AC97_EI_REV_22		0x0400	/* AC'97 revision 2.2 */
-#define AC97_EI_REV_23		0x0800	/* AC'97 revision 2.3 */
-#define AC97_EI_REV_SHIFT	10
-#define AC97_EI_ADDR_MASK	0xc000	/* physical codec ID (address) */
-#define AC97_EI_ADDR_SHIFT	14
-
-/* extended audio status and control bit defines */
-#define AC97_EA_VRA		0x0001	/* Variable bit rate enable bit */
-#define AC97_EA_DRA		0x0002	/* Double-rate audio enable bit */
-#define AC97_EA_SPDIF		0x0004	/* S/PDIF out enable bit */
-#define AC97_EA_VRM		0x0008	/* Variable bit rate for MIC enable bit */
-#define AC97_EA_SPSA_SLOT_MASK	0x0030	/* Mask for slot assignment bits */
-#define AC97_EA_SPSA_SLOT_SHIFT 4
-#define AC97_EA_SPSA_3_4	0x0000	/* Slot assigned to 3 & 4 */
-#define AC97_EA_SPSA_7_8	0x0010	/* Slot assigned to 7 & 8 */
-#define AC97_EA_SPSA_6_9	0x0020	/* Slot assigned to 6 & 9 */
-#define AC97_EA_SPSA_10_11	0x0030	/* Slot assigned to 10 & 11 */
-#define AC97_EA_CDAC		0x0040	/* PCM Center DAC is ready (Read only) */
-#define AC97_EA_SDAC		0x0080	/* PCM Surround DACs are ready (Read only) */
-#define AC97_EA_LDAC		0x0100	/* PCM LFE DAC is ready (Read only) */
-#define AC97_EA_MDAC		0x0200	/* MIC ADC is ready (Read only) */
-#define AC97_EA_SPCV		0x0400	/* S/PDIF configuration valid (Read only) */
-#define AC97_EA_PRI		0x0800	/* Turns the PCM Center DAC off */
-#define AC97_EA_PRJ		0x1000	/* Turns the PCM Surround DACs off */
-#define AC97_EA_PRK		0x2000	/* Turns the PCM LFE DAC off */
-#define AC97_EA_PRL		0x4000	/* Turns the MIC ADC off */
-
-/* S/PDIF control bit defines */
-#define AC97_SC_PRO		0x0001	/* Professional status */
-#define AC97_SC_NAUDIO		0x0002	/* Non audio stream */
-#define AC97_SC_COPY		0x0004	/* Copyright status */
-#define AC97_SC_PRE		0x0008	/* Preemphasis status */
-#define AC97_SC_CC_MASK		0x07f0	/* Category Code mask */
-#define AC97_SC_CC_SHIFT	4
-#define AC97_SC_L		0x0800	/* Generation Level status */
-#define AC97_SC_SPSR_MASK	0x3000	/* S/PDIF Sample Rate bits */
-#define AC97_SC_SPSR_SHIFT	12
-#define AC97_SC_SPSR_44K	0x0000	/* Use 44.1kHz Sample rate */
-#define AC97_SC_SPSR_48K	0x2000	/* Use 48kHz Sample rate */
-#define AC97_SC_SPSR_32K	0x3000	/* Use 32kHz Sample rate */
-#define AC97_SC_DRS		0x4000	/* Double Rate S/PDIF */
-#define AC97_SC_V		0x8000	/* Validity status */
-
-/* Interrupt and Paging bit defines (AC'97 2.3) */
-#define AC97_PAGE_MASK		0x000f	/* Page Selector */
-#define AC97_PAGE_VENDOR	0	/* Vendor-specific registers */
-#define AC97_PAGE_1		1	/* Extended Codec Registers page 1 */
-#define AC97_INT_ENABLE		0x0800	/* Interrupt Enable */
-#define AC97_INT_SENSE		0x1000	/* Sense Cycle */
-#define AC97_INT_CAUSE_SENSE	0x2000	/* Sense Cycle Completed (RO) */
-#define AC97_INT_CAUSE_GPIO	0x4000	/* GPIO bits changed (RO) */
-#define AC97_INT_STATUS		0x8000	/* Interrupt Status */
-
-/* extended modem ID bit defines */
-#define AC97_MEI_LINE1		0x0001	/* Line1 present */
-#define AC97_MEI_LINE2		0x0002	/* Line2 present */
-#define AC97_MEI_HANDSET	0x0004	/* Handset present */
-#define AC97_MEI_CID1		0x0008	/* caller ID decode for Line1 is supported */
-#define AC97_MEI_CID2		0x0010	/* caller ID decode for Line2 is supported */
-#define AC97_MEI_ADDR_MASK	0xc000	/* physical codec ID (address) */
-#define AC97_MEI_ADDR_SHIFT	14
-
-/* extended modem status and control bit defines */
-#define AC97_MEA_GPIO		0x0001	/* GPIO is ready (ro) */
-#define AC97_MEA_MREF		0x0002	/* Vref is up to nominal level (ro) */
-#define AC97_MEA_ADC1		0x0004	/* ADC1 operational (ro) */
-#define AC97_MEA_DAC1		0x0008	/* DAC1 operational (ro) */
-#define AC97_MEA_ADC2		0x0010	/* ADC2 operational (ro) */
-#define AC97_MEA_DAC2		0x0020	/* DAC2 operational (ro) */
-#define AC97_MEA_HADC		0x0040	/* HADC operational (ro) */
-#define AC97_MEA_HDAC		0x0080	/* HDAC operational (ro) */
-#define AC97_MEA_PRA		0x0100	/* GPIO power down (high) */
-#define AC97_MEA_PRB		0x0200	/* reserved */
-#define AC97_MEA_PRC		0x0400	/* ADC1 power down (high) */
-#define AC97_MEA_PRD		0x0800	/* DAC1 power down (high) */
-#define AC97_MEA_PRE		0x1000	/* ADC2 power down (high) */
-#define AC97_MEA_PRF		0x2000	/* DAC2 power down (high) */
-#define AC97_MEA_PRG		0x4000	/* HADC power down (high) */
-#define AC97_MEA_PRH		0x8000	/* HDAC power down (high) */
-
-/* modem gpio status defines */
-#define AC97_GPIO_LINE1_OH      0x0001  /* Off Hook Line1 */
-#define AC97_GPIO_LINE1_RI      0x0002  /* Ring Detect Line1 */
-#define AC97_GPIO_LINE1_CID     0x0004  /* Caller ID path enable Line1 */
-#define AC97_GPIO_LINE1_LCS     0x0008  /* Loop Current Sense Line1 */
-#define AC97_GPIO_LINE1_PULSE   0x0010  /* Opt./ Pulse Dial Line1 (out) */
-#define AC97_GPIO_LINE1_HL1R    0x0020  /* Opt./ Handset to Line1 relay control (out) */
-#define AC97_GPIO_LINE1_HOHD    0x0040  /* Opt./ Handset off hook detect Line1 (in) */
-#define AC97_GPIO_LINE12_AC     0x0080  /* Opt./ Int.bit 1 / Line1/2 AC (out) */
-#define AC97_GPIO_LINE12_DC     0x0100  /* Opt./ Int.bit 2 / Line1/2 DC (out) */
-#define AC97_GPIO_LINE12_RS     0x0200  /* Opt./ Int.bit 3 / Line1/2 RS (out) */
-#define AC97_GPIO_LINE2_OH      0x0400  /* Off Hook Line2 */
-#define AC97_GPIO_LINE2_RI      0x0800  /* Ring Detect Line2 */
-#define AC97_GPIO_LINE2_CID     0x1000  /* Caller ID path enable Line2 */
-#define AC97_GPIO_LINE2_LCS     0x2000  /* Loop Current Sense Line2 */
-#define AC97_GPIO_LINE2_PULSE   0x4000  /* Opt./ Pulse Dial Line2 (out) */
-#define AC97_GPIO_LINE2_HL1R    0x8000  /* Opt./ Handset to Line2 relay control (out) */
-
 /* specific - SigmaTel */
 #define AC97_SIGMATEL_OUTSEL	0x64	/* Output Select, STAC9758 */
 #define AC97_SIGMATEL_INSEL	0x66	/* Input Select, STAC9758 */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 2/7] ALSA: ac97: add an ac97 bus
  2016-05-27 20:26 [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
  2016-05-27 20:26 ` [RFC PATCH v2 1/7] ALSA: ac97: split out the generic ac97 registers Robert Jarzmik
@ 2016-05-27 20:26 ` Robert Jarzmik
  2016-05-27 20:26 ` [RFC PATCH v2 3/7] ASoC: add new ac97 bus support Robert Jarzmik
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Robert Jarzmik @ 2016-05-27 20:26 UTC (permalink / raw)
  To: Robert Jarzmik, Daniel Mack, Haojian Zhuang, Jaroslav Kysela,
	Takashi Iwai, Liam Girdwood, Mark Brown
  Cc: linux-arm-kernel, linux-kernel, alsa-devel, patches

AC97 is a bus for sound usage. It enables for a AC97 AC-Link to link one
controller to 0 to 4 AC97 codecs.

The goal of this new implementation is to implement a device/driver
model for AC97, with an automatic scan of the bus and automatic
discovery of AC97 codec devices.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
Since v1:
 - Takashi's review
   - changed the codec.h guard ... a better name could be found ...
   - added the AC97_* macros missing parenthesis
   - constantified the id_table in the codec driver structure
   - changed the 4 codecs linked list into an array
   - enabled the ac97 bus to be a module
   - added a slots_available to snd_ac97_controller_register() to have a
     way to prevent scanning and probing of unconnected codecs
   - removed useless ac97 bus index
   - all exported functions begin with snd_ac97_*()
   - change bus operations to controller+slot parameters instead of
     codec device

 - Mark's review
   - changed ac97_digital_controller into ac97_controller
   - rename ac97_digital_controller_*() into ac97_controller_*()
   - add the ac97 ac-link clock to the codec device (ie. the AC'97 BIT_CLK)
---
 include/sound/ac97/codec.h      | 111 ++++++++++++
 include/sound/ac97/compat.h     |  21 +++
 include/sound/ac97/controller.h |  80 +++++++++
 sound/ac97/Kconfig              |  18 ++
 sound/ac97/Makefile             |   8 +
 sound/ac97/ac97_core.h          |  10 ++
 sound/ac97/bus.c                | 381 ++++++++++++++++++++++++++++++++++++++++
 sound/ac97/codec.c              |  15 ++
 sound/ac97/snd_ac97_compat.c    | 104 +++++++++++
 9 files changed, 748 insertions(+)
 create mode 100644 include/sound/ac97/codec.h
 create mode 100644 include/sound/ac97/compat.h
 create mode 100644 include/sound/ac97/controller.h
 create mode 100644 sound/ac97/Kconfig
 create mode 100644 sound/ac97/Makefile
 create mode 100644 sound/ac97/ac97_core.h
 create mode 100644 sound/ac97/bus.c
 create mode 100644 sound/ac97/codec.c
 create mode 100644 sound/ac97/snd_ac97_compat.c

diff --git a/include/sound/ac97/codec.h b/include/sound/ac97/codec.h
new file mode 100644
index 000000000000..a1c9746c987e
--- /dev/null
+++ b/include/sound/ac97/codec.h
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __SOUND_AC97_CODEC2_H
+#define __SOUND_AC97_CODEC2_H
+
+#include <linux/device.h>
+
+#define AC97_ID(vendor_id1, vendor_id2) \
+	((((vendor_id1) & 0xffff) << 16) | ((vendor_id2) & 0xffff))
+#define AC97_DRIVER_ID(vendor_id1, vendor_id2, mask_id1, mask_id2, _data) \
+	{ .id = (((vendor_id1) & 0xffff) << 16) | ((vendor_id2) & 0xffff), \
+	  .mask = (((mask_id1) & 0xffff) << 16) | ((mask_id2) & 0xffff), \
+	  .data = (_data) }
+
+#define to_ac97_device(d) container_of(d, struct ac97_codec_device, dev)
+#define to_ac97_driver(d) container_of(d, struct ac97_codec_driver, driver)
+
+struct ac97_controller;
+struct clk;
+
+/**
+ * struct ac97_id - matches a codec device and driver on an ac97 bus
+ * @id: The significant bits if the codec vendor ID1 and ID2
+ * @mask: Bitmask specifying which bits of the id field are significant when
+ *	  matching. A driver binds to a device when :
+ *        ((vendorID1 << 8 | vendorID2) & (mask_id1 << 8 | mask_id2)) == id.
+ * @data: Private data used by the driver.
+ */
+struct ac97_id {
+	unsigned int		id;
+	unsigned int		mask;
+	void			*data;
+};
+
+/**
+ * ac97_codec_device - a ac97 codec
+ * @dev: the core device
+ * @vendor_id: the vendor_id of the codec, as sensed on the AC-link
+ * @num: the codec number, 0 is primary, 1 is first slave, etc ...
+ * @clk: the clock BIT_CLK provided to the codec
+ * @ac97_ctrl: ac97 digital controller on the same AC-link
+ *
+ * This is the device instanciated for each codec living on a AC-link. There are
+ * normally 0 to 4 codec devices per AC-link, and all of them are controlled by
+ * an AC97 digital controller.
+ */
+struct ac97_codec_device {
+	struct device		dev;
+	unsigned int		vendor_id;
+	unsigned int		num;
+	struct clk		*clk;
+	struct ac97_controller	*ac97_ctrl;
+};
+
+/**
+ * ac97_codec_driver - a ac97 codec driver
+ * @driver: the device driver structure
+ * @probe: the function called when a ac97_codec_device is matched
+ * @remove: the function called when the device is unbound/removed
+ * @suspend: suspend function (might be NULL)
+ * @resume: resume function (might be NULL)
+ * @shutdown: shutdown function (might be NULL)
+ * @id_table: ac97 vendor_id match table, { } member terminated
+ */
+struct ac97_codec_driver {
+	struct device_driver	driver;
+	int			(*probe)(struct ac97_codec_device *);
+	int			(*remove)(struct ac97_codec_device *);
+	int			(*suspend)(struct ac97_codec_device *);
+	int			(*resume)(struct ac97_codec_device *);
+	void			(*shutdown)(struct ac97_codec_device *);
+	const struct ac97_id	*id_table;
+};
+
+#if defined(CONFIG_AC97_BUS_NEW)
+int snd_ac97_codec_driver_register(struct ac97_codec_driver *drv);
+void snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv);
+#else
+static int snd_ac97_codec_driver_register(struct ac97_codec_driver *drv)
+{
+	return 0;
+}
+static void snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv)
+{
+}
+#endif
+
+
+static inline struct device *
+ac97_codec_dev2dev(struct ac97_codec_device *adev)
+{
+	return &adev->dev;
+}
+
+static inline void *ac97_get_drvdata(struct ac97_codec_device *adev)
+{
+	return dev_get_drvdata(ac97_codec_dev2dev(adev));
+}
+
+static inline void ac97_set_drvdata(struct ac97_codec_device *adev,
+				    void *data)
+{
+	dev_set_drvdata(ac97_codec_dev2dev(adev), data);
+}
+
+#endif
diff --git a/include/sound/ac97/compat.h b/include/sound/ac97/compat.h
new file mode 100644
index 000000000000..bf611f572f2d
--- /dev/null
+++ b/include/sound/ac97/compat.h
@@ -0,0 +1,21 @@
+/*
+ *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file is for backward compatibility with snd_ac97 structure and its
+ * multiple usages, such as the snd_ac97_bus and snd_ac97_build_ops.
+ *
+ */
+#ifndef AC97_COMPAT_H
+#define AC97_COMPAT_H
+
+#include <sound/ac97_codec.h>
+#include <sound/soc.h>
+
+struct snd_ac97 *compat_alloc_snd_ac97_codec(struct snd_soc_codec *codec);
+void compat_release_snd_ac97_codec(struct snd_ac97 *ac97);
+
+#endif
diff --git a/include/sound/ac97/controller.h b/include/sound/ac97/controller.h
new file mode 100644
index 000000000000..7e677f59832a
--- /dev/null
+++ b/include/sound/ac97/controller.h
@@ -0,0 +1,80 @@
+/*
+ *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef AC97_CONTROLLER_H
+#define AC97_CONTROLLER_H
+
+#include <linux/list.h>
+
+#define AC97_BUS_MAX_CODECS 4
+#define AC97_SLOTS_AVAILABLE_ALL 0xf
+
+struct device;
+
+/**
+ * struct ac97_controller - The AC97 controller of the AC-Link
+ * @ops:		the AC97 operations.
+ * @controllers:	linked list of all existing controllers.
+ * @dev:		the device providing the AC97 controller.
+ * @slots_available:	the mask of accessible/scanable codecs.
+ * @codecs:		the 4 possible AC97 codecs (NULL if none found).
+ *
+ * This structure is internal to AC97 bus, and should not be used by the
+ * controllers themselves, excepting for using @dev.
+ */
+struct ac97_controller {
+	const struct ac97_controller_ops *ops;
+	struct list_head controllers;
+	struct device *dev;
+	unsigned short slots_available;
+	struct ac97_codec_device *codecs[AC97_BUS_MAX_CODECS];
+};
+
+/**
+ * struct ac97_controller_ops - The AC97 operations
+ * @reset:	Cold reset of the AC97 AC-Link.
+ * @warm_reset:	Warm reset of the AC97 AC-Link.
+ * @read:	Read of a single AC97 register.
+ *		Returns the register value or a negative error code.
+ * @write:	Write of a single AC97 register.
+ * @wait:	Wait for the current AC97 operation to finish (might be NULL).
+ * @init:	Initialization of the AC97 AC-Link (might be NULL).
+ *
+ * These are the basic operation an AC97 controller must provide for an AC97
+ * access functions. Amongst these, all but the last 2 are mandatory.
+ * The slot number is also known as the AC97 codec number, between 0 and 3.
+ */
+struct ac97_controller_ops {
+	void (*reset)(struct ac97_controller *adrv);
+	void (*warm_reset)(struct ac97_controller *adrv);
+	int (*write)(struct ac97_controller *adrv, int slot,
+		     unsigned short reg, unsigned short val);
+	int (*read)(struct ac97_controller *adrv, int slot, unsigned short reg);
+	void (*wait)(struct ac97_controller *adrv, int slot);
+	void (*init)(struct ac97_controller *adrv, int slot);
+};
+
+#if defined(CONFIG_AC97_BUS_NEW)
+int snd_ac97_controller_register(const struct ac97_controller_ops *ops,
+				 struct device *dev,
+				 unsigned short slots_available);
+int snd_ac97_controller_unregister(const struct device *dev);
+#else
+static int snd_ac97_controller_register(const struct ac97_controller_ops *ops,
+					struct device *dev,
+					unsigned short slots_available)
+{
+	return 0;
+}
+
+static int snd_ac97_controller_unregister(const struct device *dev)
+{
+	return 0;
+}
+#endif
+
+#endif
diff --git a/sound/ac97/Kconfig b/sound/ac97/Kconfig
new file mode 100644
index 000000000000..a99e4dbdf372
--- /dev/null
+++ b/sound/ac97/Kconfig
@@ -0,0 +1,18 @@
+#
+# AC97 configuration
+#
+
+
+config AC97_BUS_NEW
+	tristate
+	select AC97
+	help
+	  This is the new AC97 bus type, successor of AC97_BUS. The ported
+	  drivers which benefit from the AC97 automatic probing should "select"
+	  this instead of the AC97_BUS.
+	  Say Y here if you want to have AC97 devices, which are sound oriented
+	  devices around an AC-Link.
+
+config AC97_BUS_COMPAT
+       bool
+       depends on !AC97_BUS
diff --git a/sound/ac97/Makefile b/sound/ac97/Makefile
new file mode 100644
index 000000000000..f9c2640bfb59
--- /dev/null
+++ b/sound/ac97/Makefile
@@ -0,0 +1,8 @@
+#
+# make for AC97 bus drivers
+#
+
+obj-$(CONFIG_AC97_BUS_NEW)	+= ac97.o
+
+ac97-y				+= bus.o codec.o
+ac97-$(CONFIG_AC97_BUS_COMPAT)	+= snd_ac97_compat.o
diff --git a/sound/ac97/ac97_core.h b/sound/ac97/ac97_core.h
new file mode 100644
index 000000000000..db6e27288357
--- /dev/null
+++ b/sound/ac97/ac97_core.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+unsigned int ac97_bus_scan_one(struct ac97_controller *ac97,
+			       int codec_num);
diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c
new file mode 100644
index 000000000000..6755da79d4b7
--- /dev/null
+++ b/sound/ac97/bus.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/controller.h>
+#include <sound/ac97/regs.h>
+
+/*
+ * Protects ac97_controllers and each ac97_controller structure.
+ */
+static DEFINE_MUTEX(ac97_controllers_mutex);
+static LIST_HEAD(ac97_controllers);
+
+static struct bus_type ac97_bus_type;
+
+static struct ac97_codec_device *
+ac97_codec_find(struct ac97_controller *ac97_ctrl, int codec_num)
+{
+	if ((codec_num < 0) || (codec_num >= AC97_BUS_MAX_CODECS))
+		return ERR_PTR(-ERANGE);
+
+	return ac97_ctrl->codecs[codec_num];
+}
+
+static void ac97_codec_release(struct device *dev)
+{
+	struct ac97_codec_device *adev;
+	struct ac97_controller *ac97_ctrl;
+
+	adev = container_of(dev, struct ac97_codec_device, dev);
+	ac97_ctrl = adev->ac97_ctrl;
+	ac97_ctrl->codecs[adev->num] = NULL;
+	kfree(adev);
+}
+
+static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,
+		   unsigned int vendor_id)
+{
+	struct ac97_codec_device *codec;
+	char *codec_name;
+	int ret;
+
+	codec = kzalloc(sizeof(*codec), GFP_KERNEL);
+	if (!codec)
+		return -ENOMEM;
+	ac97_ctrl->codecs[idx] = codec;
+	codec->vendor_id = vendor_id;
+	codec->dev.release = ac97_codec_release;
+	codec->dev.bus = &ac97_bus_type;
+	codec->dev.parent = ac97_ctrl->dev;
+	codec->num = idx;
+	codec->ac97_ctrl = ac97_ctrl;
+
+	codec_name = kasprintf(GFP_KERNEL, "%s:%d", dev_name(ac97_ctrl->dev),
+			       idx);
+	codec->dev.init_name = codec_name;
+
+	ret = device_register(&codec->dev);
+	kfree(codec_name);
+	if (ret) {
+		kfree(codec);
+		ac97_ctrl->codecs[idx] = NULL;
+	}
+
+	return ret;
+}
+
+unsigned int ac97_bus_scan_one(struct ac97_controller *adrv,
+				      int codec_num)
+{
+	unsigned short vid1, vid2;
+	int ret;
+
+	ret = adrv->ops->read(adrv, codec_num, AC97_VENDOR_ID1);
+	vid1 = (ret & 0xffff);
+	if (ret < 0)
+		return 0;
+
+	ret = adrv->ops->read(adrv, codec_num, AC97_VENDOR_ID2);
+	vid2 = (ret & 0xffff);
+	if (ret < 0)
+		return 0;
+
+	dev_dbg(adrv->dev, "%s(codec_num=%d): vendor_id=0x%08x\n",
+		__func__, codec_num, AC97_ID(vid1, vid2));
+	return AC97_ID(vid1, vid2);
+}
+
+static int ac97_bus_scan(struct ac97_controller *ac97_ctrl)
+{
+	int ret, i;
+	unsigned int vendor_id;
+
+	for (i = 0; i < AC97_BUS_MAX_CODECS; i++) {
+		if (ac97_codec_find(ac97_ctrl, i))
+			continue;
+		if (!(ac97_ctrl->slots_available & BIT(i)))
+			continue;
+		vendor_id = ac97_bus_scan_one(ac97_ctrl, i);
+		if (!vendor_id)
+			continue;
+
+		ret = ac97_codec_add(ac97_ctrl, i, vendor_id);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static void ac97_rescan_all_controllers(void)
+{
+	struct ac97_controller *ac97_ctrl;
+	int ret;
+
+	mutex_lock(&ac97_controllers_mutex);
+	list_for_each_entry(ac97_ctrl, &ac97_controllers, controllers) {
+		ret = ac97_bus_scan(ac97_ctrl);
+		if (ret)
+			dev_warn(ac97_ctrl->dev, "scan failed: %d\n", ret);
+	}
+	mutex_unlock(&ac97_controllers_mutex);
+}
+
+static int ac97_bus_reset(struct ac97_controller *ac97_ctrl)
+{
+	ac97_ctrl->ops->reset(ac97_ctrl);
+
+	return 0;
+}
+
+/**
+ * snd_ac97_codec_driver_register - register an AC97 codec driver
+ * @dev: AC97 driver codec to register
+ *
+ * Register an AC97 codec driver to the ac97 bus driver, aka. the AC97 digital
+ * controller.
+ *
+ * Returns 0 on success or error code
+ */
+int snd_ac97_codec_driver_register(struct ac97_codec_driver *drv)
+{
+	int ret;
+
+	drv->driver.bus = &ac97_bus_type;
+
+	ret = driver_register(&drv->driver);
+	if (!ret)
+		ac97_rescan_all_controllers();
+
+	return ret;
+}
+EXPORT_SYMBOL(snd_ac97_codec_driver_register);
+
+/**
+ * snd_ac97_codec_driver_unregister - unregister an AC97 codec driver
+ * @dev: AC97 codec driver to unregister
+ *
+ * Unregister a previously registered ac97 codec driver.
+ */
+void snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(snd_ac97_codec_driver_unregister);
+
+static int ac97_ctrl_codecs_unregister(struct ac97_controller *ac97_ctrl)
+{
+	int i;
+
+	for (i = 0; i < AC97_BUS_MAX_CODECS; i++)
+		if (ac97_ctrl->codecs[i])
+			put_device(&ac97_ctrl->codecs[i]->dev);
+
+	return 0;
+}
+
+/**
+ * snd_ac97_controller_register - register an ac97 controller
+ * @ops: the ac97 bus operations
+ * @dev: the device providing the ac97 DC function
+ * @slots_available: mask of the ac97 codecs that can be scanned and probed
+ *                   bit0 => codec 0, bit1 => codec 1 ... bit 3 => codec 3
+ *
+ * Register a digital controller which can control up to 4 ac97 codecs. This is
+ * the controller side of the AC97 AC-link, while the slave side are the codecs.
+ *
+ * Returns 0 upon success, negative value upon error
+ */
+int snd_ac97_controller_register(const struct ac97_controller_ops *ops,
+				 struct device *dev,
+				 unsigned short slots_available)
+{
+	struct ac97_controller *ac97_ctrl;
+
+	ac97_ctrl = kzalloc(sizeof(*ac97_ctrl), GFP_KERNEL);
+	if (!ac97_ctrl)
+		return -ENOMEM;
+
+	mutex_lock(&ac97_controllers_mutex);
+	ac97_ctrl->ops = ops;
+	ac97_ctrl->slots_available = slots_available;
+	ac97_ctrl->dev = dev;
+	list_add(&ac97_ctrl->controllers, &ac97_controllers);
+	mutex_unlock(&ac97_controllers_mutex);
+
+	ac97_bus_reset(ac97_ctrl);
+	ac97_bus_scan(ac97_ctrl);
+
+	return 0;
+}
+EXPORT_SYMBOL(snd_ac97_controller_register);
+
+/**
+ * snd_ac97_controller_unregister - unregister an ac97 controller
+ * @dev: the device previously provided to ac97_controller_register()
+ *
+ * Returns 0 on success, negative upon error
+ */
+int snd_ac97_controller_unregister(const struct device *dev)
+{
+	struct ac97_controller *ac97_ctrl, *tmp;
+	int ret = -ENODEV, i;
+
+	mutex_lock(&ac97_controllers_mutex);
+	list_for_each_entry_safe(ac97_ctrl, tmp, &ac97_controllers,
+				 controllers) {
+		if (ac97_ctrl->dev != dev)
+			continue;
+		ret = 0;
+		for (i = 0; i < AC97_BUS_MAX_CODECS; i++)
+			if (ac97_ctrl->codecs[i] &&
+			    device_is_registered(&ac97_ctrl->codecs[i]->dev))
+				ret = -EBUSY;
+		if (!ret)
+			ret = ac97_ctrl_codecs_unregister(ac97_ctrl);
+		if (!ret)
+			list_del(&ac97_ctrl->controllers);
+	}
+
+	mutex_unlock(&ac97_controllers_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(snd_ac97_controller_unregister);
+
+static const struct dev_pm_ops ac97_pm = {
+	.suspend	= pm_generic_suspend,
+	.resume		= pm_generic_resume,
+	.freeze		= pm_generic_freeze,
+	.thaw		= pm_generic_thaw,
+	.poweroff	= pm_generic_poweroff,
+	.restore	= pm_generic_restore,
+};
+
+static int ac97_get_enable_clk(struct ac97_codec_device *adev)
+{
+	int ret;
+
+	adev->clk = clk_get(&adev->dev, "ac97_clk");
+	if (IS_ERR(adev->clk))
+		return PTR_ERR(adev->clk);
+
+	ret = clk_prepare_enable(adev->clk);
+	if (ret)
+		clk_put(adev->clk);
+
+	return ret;
+}
+
+static void ac97_put_disable_clk(struct ac97_codec_device *adev)
+{
+	clk_disable_unprepare(adev->clk);
+	clk_put(adev->clk);
+}
+
+static ssize_t vendor_id_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct ac97_codec_device *codec = to_ac97_device(dev);
+
+	return sprintf(buf, "%08x", codec->vendor_id);
+}
+
+static struct device_attribute ac97_dev_attrs[] = {
+	__ATTR_RO(vendor_id),
+	__ATTR_NULL,
+};
+
+static int ac97_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct ac97_codec_device *adev = to_ac97_device(dev);
+	struct ac97_codec_driver *adrv = to_ac97_driver(drv);
+	const struct ac97_id *id = adrv->id_table;
+	int i = 0;
+
+	if (adev->vendor_id == 0x0 || adev->vendor_id == 0xffffffff)
+		return false;
+
+	do {
+		if ((id[i].id & id->mask) == (adev->vendor_id & id[i].mask))
+			return true;
+	} while (id[i++].id);
+
+	return false;
+}
+
+static int ac97_bus_probe(struct device *dev)
+{
+	struct ac97_codec_device *adev = to_ac97_device(dev);
+	struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);
+	int ret;
+
+	ret = ac97_get_enable_clk(adev);
+	if (ret)
+		return ret;
+
+	pm_runtime_get_noresume(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	ret = adrv->probe(adev);
+	if (ret == 0)
+		return 0;
+
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	pm_runtime_put_noidle(dev);
+	ac97_put_disable_clk(adev);
+
+	return ret;
+}
+
+static int ac97_bus_remove(struct device *dev)
+{
+	struct ac97_codec_device *adev = to_ac97_device(dev);
+	struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);
+	int ret;
+
+	ret = pm_runtime_get_sync(dev);
+	if (ret)
+		return ret;
+
+	ret = adrv->remove(adev);
+	pm_runtime_put_noidle(dev);
+	if (ret == 0)
+		ac97_put_disable_clk(adev);
+
+	return ret;
+}
+
+static struct bus_type ac97_bus_type = {
+	.name		= "ac97",
+	.dev_attrs	= ac97_dev_attrs,
+	.match		= ac97_bus_match,
+	.pm		= &ac97_pm,
+	.probe		= ac97_bus_probe,
+	.remove		= ac97_bus_remove,
+};
+
+static int __init ac97_bus_init(void)
+{
+	return bus_register(&ac97_bus_type);
+}
+subsys_initcall(ac97_bus_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
diff --git a/sound/ac97/codec.c b/sound/ac97/codec.c
new file mode 100644
index 000000000000..a835f03744bf
--- /dev/null
+++ b/sound/ac97/codec.c
@@ -0,0 +1,15 @@
+/*
+ *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <sound/ac97_codec.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/controller.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>	/* For compat_ac97_* */
+
diff --git a/sound/ac97/snd_ac97_compat.c b/sound/ac97/snd_ac97_compat.c
new file mode 100644
index 000000000000..15ed77c8cf06
--- /dev/null
+++ b/sound/ac97/snd_ac97_compat.c
@@ -0,0 +1,104 @@
+/*
+ *  Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/controller.h>
+#include <sound/soc.h>
+
+#include "ac97_core.h"
+
+static void compat_ac97_reset(struct snd_ac97 *ac97)
+{
+	struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
+	struct ac97_controller *actrl = adev->ac97_ctrl;
+
+	if (actrl->ops->reset)
+		actrl->ops->reset(actrl);
+}
+
+static void compat_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+	struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
+	struct ac97_controller *actrl = adev->ac97_ctrl;
+
+	if (actrl->ops->warm_reset)
+		actrl->ops->warm_reset(actrl);
+}
+
+static void compat_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+			      unsigned short val)
+{
+	struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
+	struct ac97_controller *actrl = adev->ac97_ctrl;
+
+	actrl->ops->write(actrl, ac97->num, reg, val);
+}
+
+static unsigned short compat_ac97_read(struct snd_ac97 *ac97,
+				       unsigned short reg)
+{
+	struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
+	struct ac97_controller *actrl = adev->ac97_ctrl;
+
+	return actrl->ops->read(actrl, ac97->num, reg);
+}
+
+static struct snd_ac97_bus_ops compat_snd_ac97_bus_ops = {
+	.reset = compat_ac97_reset,
+	.warm_reset = compat_ac97_warm_reset,
+	.write = compat_ac97_write,
+	.read = compat_ac97_read,
+};
+
+static struct snd_ac97_bus compat_soc_ac97_bus = {
+	.ops = &compat_snd_ac97_bus_ops,
+};
+
+struct snd_ac97 *compat_alloc_snd_ac97_codec(struct snd_soc_codec *codec)
+{
+	struct snd_ac97 *ac97;
+
+	ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
+	if (ac97 == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	ac97->dev = *codec->dev;
+	ac97->private_data = codec->dev;
+	ac97->bus = &compat_soc_ac97_bus;
+	return ac97;
+}
+EXPORT_SYMBOL_GPL(compat_alloc_snd_ac97_codec);
+
+void compat_release_snd_ac97_codec(struct snd_ac97 *ac97)
+{
+	kfree(ac97);
+}
+EXPORT_SYMBOL_GPL(compat_release_snd_ac97_codec);
+
+int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
+	unsigned int id_mask)
+{
+	struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
+	struct ac97_controller *actrl = adev->ac97_ctrl;
+
+	if (try_warm) {
+		compat_ac97_warm_reset(ac97);
+		if (ac97_bus_scan_one(actrl, adev->num) == adev->vendor_id)
+			return 1;
+	}
+
+	compat_ac97_reset(ac97);
+	compat_ac97_warm_reset(ac97);
+	if (ac97_bus_scan_one(actrl, adev->num) == adev->vendor_id)
+		return 0;
+
+	return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(snd_ac97_reset);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 3/7] ASoC: add new ac97 bus support
  2016-05-27 20:26 [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
  2016-05-27 20:26 ` [RFC PATCH v2 1/7] ALSA: ac97: split out the generic ac97 registers Robert Jarzmik
  2016-05-27 20:26 ` [RFC PATCH v2 2/7] ALSA: ac97: add an ac97 bus Robert Jarzmik
@ 2016-05-27 20:26 ` Robert Jarzmik
  2016-05-27 20:26 ` [RFC PATCH v2 4/7] ASoC: wm9713: add ac97 new " Robert Jarzmik
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Robert Jarzmik @ 2016-05-27 20:26 UTC (permalink / raw)
  To: Robert Jarzmik, Daniel Mack, Haojian Zhuang, Jaroslav Kysela,
	Takashi Iwai, Liam Girdwood, Mark Brown
  Cc: linux-arm-kernel, linux-kernel, alsa-devel, patches

Add the new ac97 bus support, with ac97 bus automatic probing.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 sound/Kconfig     | 2 ++
 sound/Makefile    | 1 +
 sound/soc/Kconfig | 4 ++++
 3 files changed, 7 insertions(+)

diff --git a/sound/Kconfig b/sound/Kconfig
index 5a240e050ae6..c7e1cbe84951 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -80,6 +80,8 @@ source "sound/hda/Kconfig"
 
 source "sound/ppc/Kconfig"
 
+source "sound/ac97/Kconfig"
+
 source "sound/aoa/Kconfig"
 
 source "sound/arm/Kconfig"
diff --git a/sound/Makefile b/sound/Makefile
index 77320709fd26..74728aee25d5 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
 obj-$(CONFIG_AC97_BUS) += ac97_bus.o
+obj-$(CONFIG_AC97_BUS_NEW) += ac97/
 
 ifeq ($(CONFIG_SND),y)
   obj-y += last.o
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 182d92efc7c8..5ad0a0422054 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -6,6 +6,7 @@ menuconfig SND_SOC
 	tristate "ALSA for SoC audio support"
 	select SND_PCM
 	select AC97_BUS if SND_SOC_AC97_BUS
+	select AC97_BUS_NEW if SND_SOC_AC97_BUS_NEW
 	select SND_JACK
 	select REGMAP_I2C if I2C
 	select REGMAP_SPI if SPI_MASTER
@@ -25,6 +26,9 @@ if SND_SOC
 config SND_SOC_AC97_BUS
 	bool
 
+config SND_SOC_AC97_BUS_NEW
+	bool
+
 config SND_SOC_GENERIC_DMAENGINE_PCM
 	bool
 	select SND_DMAENGINE_PCM
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 4/7] ASoC: wm9713: add ac97 new bus support
  2016-05-27 20:26 [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
                   ` (2 preceding siblings ...)
  2016-05-27 20:26 ` [RFC PATCH v2 3/7] ASoC: add new ac97 bus support Robert Jarzmik
@ 2016-05-27 20:26 ` Robert Jarzmik
  2016-05-27 20:26 ` [RFC PATCH v2 5/7] ASoC: pxa: switch to new ac97 " Robert Jarzmik
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Robert Jarzmik @ 2016-05-27 20:26 UTC (permalink / raw)
  To: Robert Jarzmik, Daniel Mack, Haojian Zhuang, Jaroslav Kysela,
	Takashi Iwai, Liam Girdwood, Mark Brown
  Cc: linux-arm-kernel, linux-kernel, alsa-devel, patches

Add support for the new ac97 bus model, where devices are automatically
discovered on AC-Links.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 sound/soc/codecs/Kconfig  |  1 +
 sound/soc/codecs/wm9713.c | 62 ++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 649e92a252ae..2566962c990e 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -977,6 +977,7 @@ config SND_SOC_WM9712
 config SND_SOC_WM9713
 	tristate
 	select REGMAP_AC97
+	select AC97_BUS_COMPAT
 
 # Amp
 config SND_SOC_LM4857
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 9849643ef809..6cbbf4eda5fc 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -22,7 +22,8 @@
 #include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
-#include <sound/ac97_codec.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/compat.h>
 #include <sound/initval.h>
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
@@ -1207,14 +1208,13 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
 	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
 	struct regmap *regmap;
 
-	wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID,
-		WM9713_VENDOR_ID_MASK);
+	wm9713->ac97 = compat_alloc_snd_ac97_codec(codec);
 	if (IS_ERR(wm9713->ac97))
 		return PTR_ERR(wm9713->ac97);
 
 	regmap = regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config);
 	if (IS_ERR(regmap)) {
-		snd_soc_free_ac97_codec(wm9713->ac97);
+		compat_release_snd_ac97_codec(wm9713->ac97);
 		return PTR_ERR(regmap);
 	}
 
@@ -1231,7 +1231,7 @@ static int wm9713_soc_remove(struct snd_soc_codec *codec)
 	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
 
 	snd_soc_codec_exit_regmap(codec);
-	snd_soc_free_ac97_codec(wm9713->ac97);
+	compat_release_snd_ac97_codec(wm9713->ac97);
 	return 0;
 }
 
@@ -1281,7 +1281,57 @@ static struct platform_driver wm9713_codec_driver = {
 	.remove = wm9713_remove,
 };
 
-module_platform_driver(wm9713_codec_driver);
+static int wm9713_ac97_probe(struct ac97_codec_device *adev)
+{
+	struct wm9713_priv *wm9713;
+
+	wm9713 = devm_kzalloc(ac97_codec_dev2dev(adev),
+			      sizeof(*wm9713), GFP_KERNEL);
+	if (wm9713 == NULL)
+		return -ENOMEM;
+
+	mutex_init(&wm9713->lock);
+
+	ac97_set_drvdata(adev, wm9713);
+
+	return snd_soc_register_codec(ac97_codec_dev2dev(adev),
+				      &soc_codec_dev_wm9713, wm9713_dai,
+				      ARRAY_SIZE(wm9713_dai));
+}
+
+static int wm9713_ac97_remove(struct ac97_codec_device *adev)
+{
+	snd_soc_unregister_codec(ac97_codec_dev2dev(adev));
+	return 0;
+}
+
+static struct ac97_id wm9713_ac97_ids[] = {
+	{ .id = WM9713_VENDOR_ID, .mask = WM9713_VENDOR_ID_MASK },
+	{ }
+};
+
+static struct ac97_codec_driver wm9713_ac97_driver = {
+	.driver = {
+			.name = "wm9713-codec",
+	},
+	.probe		= wm9713_ac97_probe,
+	.remove		= wm9713_ac97_remove,
+	.id_table	= wm9713_ac97_ids,
+};
+
+static int __init wm9713_init(void)
+{
+	snd_ac97_codec_driver_register(&wm9713_ac97_driver);
+	return platform_driver_register(&wm9713_codec_driver);
+}
+module_init(wm9713_init);
+
+static void __exit wm9713_exit(void)
+{
+	snd_ac97_codec_driver_unregister(&wm9713_ac97_driver);
+	return platform_driver_unregister(&wm9713_codec_driver);
+}
+module_exit(wm9713_exit);
 
 MODULE_DESCRIPTION("ASoC WM9713/WM9714 driver");
 MODULE_AUTHOR("Liam Girdwood");
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 5/7] ASoC: pxa: switch to new ac97 bus support
  2016-05-27 20:26 [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
                   ` (3 preceding siblings ...)
  2016-05-27 20:26 ` [RFC PATCH v2 4/7] ASoC: wm9713: add ac97 new " Robert Jarzmik
@ 2016-05-27 20:26 ` Robert Jarzmik
  2016-05-27 20:26 ` [RFC PATCH v2 6/7] ARM: pxa: mioa701 convert to the new AC97 bus Robert Jarzmik
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Robert Jarzmik @ 2016-05-27 20:26 UTC (permalink / raw)
  To: Robert Jarzmik, Daniel Mack, Haojian Zhuang, Jaroslav Kysela,
	Takashi Iwai, Liam Girdwood, Mark Brown
  Cc: linux-arm-kernel, linux-kernel, alsa-devel, patches

Switch to the new ac97 bus support in sound/ac97 instead of the legacy
snd_ac97 one.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 include/sound/pxa2xx-lib.h  | 15 +++++++++------
 sound/arm/Kconfig           |  1 -
 sound/arm/pxa2xx-ac97-lib.c | 39 +++++++++++++++++++++++----------------
 sound/soc/pxa/Kconfig       |  4 ++--
 sound/soc/pxa/pxa2xx-ac97.c | 20 +++++++++++---------
 5 files changed, 45 insertions(+), 34 deletions(-)

diff --git a/include/sound/pxa2xx-lib.h b/include/sound/pxa2xx-lib.h
index 6ef629bde164..0e2b8ae3e00e 100644
--- a/include/sound/pxa2xx-lib.h
+++ b/include/sound/pxa2xx-lib.h
@@ -2,7 +2,8 @@
 #define PXA2XX_LIB_H
 
 #include <linux/platform_device.h>
-#include <sound/ac97_codec.h>
+#include <sound/ac97/controller.h>
+#include <sound/ac97/compat.h>
 
 /* PCM */
 
@@ -21,12 +22,14 @@ extern void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm);
 
 /* AC97 */
 
-extern unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
-extern void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val);
+extern int pxa2xx_ac97_read(struct ac97_controller *adrv, int slot,
+			    unsigned short reg);
+extern int pxa2xx_ac97_write(struct ac97_controller *adrv, int slot,
+			     unsigned short reg, unsigned short val);
 
-extern bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97);
-extern bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97);
-extern void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97);
+extern bool pxa2xx_ac97_try_warm_reset(struct ac97_controller *adrv);
+extern bool pxa2xx_ac97_try_cold_reset(struct ac97_controller *adrv);
+extern void pxa2xx_ac97_finish_reset(struct ac97_controller *adrv);
 
 extern int pxa2xx_ac97_hw_suspend(void);
 extern int pxa2xx_ac97_hw_resume(void);
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index e0406211716b..94f7539a2c1f 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -11,7 +11,6 @@ menuconfig SND_ARM
 
 config SND_PXA2XX_LIB
 	tristate
-	select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
 	select SND_DMAENGINE_PCM
 
 config SND_PXA2XX_LIB_AC97
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
index 39c3969ac1c7..62b31e909d31 100644
--- a/sound/arm/pxa2xx-ac97-lib.c
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -20,7 +20,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 
-#include <sound/ac97_codec.h>
+#include <sound/ac97/controller.h>
 #include <sound/pxa2xx-lib.h>
 
 #include <mach/irqs.h>
@@ -46,38 +46,41 @@ extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio);
  * 1 jiffy timeout if interrupt never comes).
  */
 
-unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+int pxa2xx_ac97_read(struct ac97_controller *ac97, int slot, unsigned short reg)
 {
-	unsigned short val = -1;
+	int val = -ENODEV;
 	volatile u32 *reg_addr;
 
+	if (slot > 0)
+		return -ENODEV;
+
 	mutex_lock(&car_mutex);
 
 	/* set up primary or secondary codec space */
 	if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
-		reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
+		reg_addr = slot ? &SMC_REG_BASE : &PMC_REG_BASE;
 	else
-		reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+		reg_addr = slot ? &SAC_REG_BASE : &PAC_REG_BASE;
 	reg_addr += (reg >> 1);
 
 	/* start read access across the ac97 link */
 	GSR = GSR_CDONE | GSR_SDONE;
 	gsr_bits = 0;
-	val = *reg_addr;
+	val = (*reg_addr & 0xffff);
 	if (reg == AC97_GPIO_STATUS)
 		goto out;
 	if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 &&
 	    !((GSR | gsr_bits) & GSR_SDONE)) {
 		printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
 				__func__, reg, GSR | gsr_bits);
-		val = -1;
+		val = -ETIMEDOUT;
 		goto out;
 	}
 
 	/* valid data now */
 	GSR = GSR_CDONE | GSR_SDONE;
 	gsr_bits = 0;
-	val = *reg_addr;
+	val = (*reg_addr & 0xffff);
 	/* but we've just started another cycle... */
 	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
 
@@ -86,29 +89,33 @@ out:	mutex_unlock(&car_mutex);
 }
 EXPORT_SYMBOL_GPL(pxa2xx_ac97_read);
 
-void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-			unsigned short val)
+int pxa2xx_ac97_write(struct ac97_controller *ac97, int slot,
+		      unsigned short reg, unsigned short val)
 {
 	volatile u32 *reg_addr;
+	int ret = 0;
 
 	mutex_lock(&car_mutex);
 
 	/* set up primary or secondary codec space */
 	if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
-		reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
+		reg_addr = slot ? &SMC_REG_BASE : &PMC_REG_BASE;
 	else
-		reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+		reg_addr = slot ? &SAC_REG_BASE : &PAC_REG_BASE;
 	reg_addr += (reg >> 1);
 
 	GSR = GSR_CDONE | GSR_SDONE;
 	gsr_bits = 0;
 	*reg_addr = val;
 	if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 &&
-	    !((GSR | gsr_bits) & GSR_CDONE))
+	    !((GSR | gsr_bits) & GSR_CDONE)) {
 		printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
 				__func__, reg, GSR | gsr_bits);
+		ret = -EIO;
+	}
 
 	mutex_unlock(&car_mutex);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(pxa2xx_ac97_write);
 
@@ -188,7 +195,7 @@ static inline void pxa_ac97_cold_pxa3xx(void)
 }
 #endif
 
-bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
+bool pxa2xx_ac97_try_warm_reset(struct ac97_controller *adrv)
 {
 	unsigned long gsr;
 	unsigned int timeout = 100;
@@ -225,7 +232,7 @@ bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
 }
 EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
 
-bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
+bool pxa2xx_ac97_try_cold_reset(struct ac97_controller *adrv)
 {
 	unsigned long gsr;
 	unsigned int timeout = 1000;
@@ -263,7 +270,7 @@ bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
 EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset);
 
 
-void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97)
+void pxa2xx_ac97_finish_reset(struct ac97_controller *adrv)
 {
 	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
 	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index f2bf8661dd21..784e6dedf5bf 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -23,9 +23,9 @@ config SND_PXA2XX_AC97
 
 config SND_PXA2XX_SOC_AC97
 	tristate
-	select AC97_BUS
+	select AC97_BUS_NEW
 	select SND_PXA2XX_LIB_AC97
-	select SND_SOC_AC97_BUS
+	select SND_SOC_AC97_BUS_NEW
 
 config SND_PXA2XX_SOC_I2S
 	tristate
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index f3de615aacd7..b6551be7c7eb 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -17,6 +17,7 @@
 #include <linux/dmaengine.h>
 #include <linux/dma/pxa-dma.h>
 
+#include <sound/ac97/controller.h>
 #include <sound/core.h>
 #include <sound/ac97_codec.h>
 #include <sound/soc.h>
@@ -29,21 +30,21 @@
 
 #include "pxa2xx-ac97.h"
 
-static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
+static void pxa2xx_ac97_warm_reset(struct ac97_controller *adrv)
 {
-	pxa2xx_ac97_try_warm_reset(ac97);
+	pxa2xx_ac97_try_warm_reset(adrv);
 
-	pxa2xx_ac97_finish_reset(ac97);
+	pxa2xx_ac97_finish_reset(adrv);
 }
 
-static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
+static void pxa2xx_ac97_cold_reset(struct ac97_controller *adrv)
 {
-	pxa2xx_ac97_try_cold_reset(ac97);
+	pxa2xx_ac97_try_cold_reset(adrv);
 
-	pxa2xx_ac97_finish_reset(ac97);
+	pxa2xx_ac97_finish_reset(adrv);
 }
 
-static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
+static struct ac97_controller_ops pxa2xx_ac97_ops = {
 	.read	= pxa2xx_ac97_read,
 	.write	= pxa2xx_ac97_write,
 	.warm_reset	= pxa2xx_ac97_warm_reset,
@@ -236,7 +237,8 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = snd_soc_set_ac97_ops(&pxa2xx_ac97_ops);
+	ret = snd_ac97_controller_register(&pxa2xx_ac97_ops, &pdev->dev,
+					   AC97_SLOTS_AVAILABLE_ALL);
 	if (ret != 0)
 		return ret;
 
@@ -251,7 +253,7 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 static int pxa2xx_ac97_dev_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_component(&pdev->dev);
-	snd_soc_set_ac97_ops(NULL);
+	snd_ac97_controller_unregister(&pdev->dev);
 	pxa2xx_ac97_hw_remove(pdev);
 	return 0;
 }
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 6/7] ARM: pxa: mioa701 convert to the new AC97 bus
  2016-05-27 20:26 [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
                   ` (4 preceding siblings ...)
  2016-05-27 20:26 ` [RFC PATCH v2 5/7] ASoC: pxa: switch to new ac97 " Robert Jarzmik
@ 2016-05-27 20:26 ` Robert Jarzmik
  2016-05-27 20:26 ` [RFC PATCH v2 7/7] ASoC: mioa701_wm9713: convert to new ac97 bus Robert Jarzmik
  2016-08-23 16:39 ` [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
  7 siblings, 0 replies; 11+ messages in thread
From: Robert Jarzmik @ 2016-05-27 20:26 UTC (permalink / raw)
  To: Robert Jarzmik, Daniel Mack, Haojian Zhuang, Jaroslav Kysela,
	Takashi Iwai, Liam Girdwood, Mark Brown
  Cc: linux-arm-kernel, linux-kernel, alsa-devel, patches

This migration implies :
 - wm9713 device is removed, it will be auto-probed
 - the AC97 bit clock is added as the pxa internally generated 13MHz
   clock

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 arch/arm/mach-pxa/mioa701.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index 38a96a193dc4..e26bace43147 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -19,6 +19,7 @@
  *
  */
 
+#include <linux/clkdev.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
@@ -682,7 +683,6 @@ MIO_SIMPLE_DEV(mioa701_led,	  "leds-gpio",	    &gpio_led_info)
 MIO_SIMPLE_DEV(pxa2xx_pcm,	  "pxa2xx-pcm",	    NULL)
 MIO_SIMPLE_DEV(mioa701_sound,	  "mioa701-wm9713", NULL)
 MIO_SIMPLE_DEV(mioa701_board,	  "mioa701-board",  NULL)
-MIO_SIMPLE_DEV(wm9713_acodec,	  "wm9713-codec",   NULL);
 MIO_SIMPLE_DEV(gpio_vbus,	  "gpio-vbus",      &gpio_vbus_data);
 MIO_SIMPLE_DEV(mioa701_camera,	  "soc-camera-pdrv",&iclink);
 
@@ -690,7 +690,6 @@ static struct platform_device *devices[] __initdata = {
 	&mioa701_gpio_keys,
 	&mioa701_backlight,
 	&mioa701_led,
-	&wm9713_acodec,
 	&pxa2xx_pcm,
 	&mioa701_sound,
 	&power_dev,
@@ -742,6 +741,15 @@ static void __init mioa701_machine_init(void)
 	__raw_writel(0x0001c391, MCATT0);
 	__raw_writel(0x0001c391, MCIO0);
 
+	rc = clk_add_alias("ac97_clk", "pxa2xx-ac97:0", "AC97CONFCLK",
+			   &pxa_device_ac97.dev);
+	if (rc)
+		pr_err("PXA2xx AC97 clock1 alias error: %d\n", rc);
+
+	rc = clk_add_alias("ac97_clk", "pxa2xx-ac97:1", "AC97CONFCLK",
+			   &pxa_device_ac97.dev);
+	if (rc)
+		pr_err("PXA2xx AC97 clock2 alias error: %d\n", rc);
 
 	pxa2xx_mfp_config(ARRAY_AND_SIZE(mioa701_pin_config));
 	pxa_set_ffuart_info(NULL);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 7/7] ASoC: mioa701_wm9713: convert to new ac97 bus
  2016-05-27 20:26 [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
                   ` (5 preceding siblings ...)
  2016-05-27 20:26 ` [RFC PATCH v2 6/7] ARM: pxa: mioa701 convert to the new AC97 bus Robert Jarzmik
@ 2016-05-27 20:26 ` Robert Jarzmik
  2016-08-23 16:39 ` [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
  7 siblings, 0 replies; 11+ messages in thread
From: Robert Jarzmik @ 2016-05-27 20:26 UTC (permalink / raw)
  To: Robert Jarzmik, Daniel Mack, Haojian Zhuang, Jaroslav Kysela,
	Takashi Iwai, Liam Girdwood, Mark Brown
  Cc: linux-arm-kernel, linux-kernel, alsa-devel, patches

Convert to the new auto-probing ac97 bus, which changes the device name.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 sound/soc/pxa/mioa701_wm9713.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index 5c8f9db50a47..4ed10e6ff5d1 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -149,7 +149,7 @@ static struct snd_soc_dai_link mioa701_dai[] = {
 		.stream_name = "AC97 HiFi",
 		.cpu_dai_name = "pxa2xx-ac97",
 		.codec_dai_name = "wm9713-hifi",
-		.codec_name = "wm9713-codec",
+		.codec_name = "pxa2xx-ac97:0",
 		.init = mioa701_wm9713_init,
 		.platform_name = "pxa-pcm-audio",
 		.ops = &mioa701_ops,
@@ -159,7 +159,7 @@ static struct snd_soc_dai_link mioa701_dai[] = {
 		.stream_name = "AC97 Aux",
 		.cpu_dai_name = "pxa2xx-ac97-aux",
 		.codec_dai_name ="wm9713-aux",
-		.codec_name = "wm9713-codec",
+		.codec_name = "pxa2xx-ac97:0",
 		.platform_name = "pxa-pcm-audio",
 		.ops = &mioa701_ops,
 	},
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH v2 0/7] AC97 device/driver model revamp
  2016-05-27 20:26 [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
                   ` (6 preceding siblings ...)
  2016-05-27 20:26 ` [RFC PATCH v2 7/7] ASoC: mioa701_wm9713: convert to new ac97 bus Robert Jarzmik
@ 2016-08-23 16:39 ` Robert Jarzmik
  2016-08-24 11:39   ` Mark Brown
  7 siblings, 1 reply; 11+ messages in thread
From: Robert Jarzmik @ 2016-08-23 16:39 UTC (permalink / raw)
  To: Mark Brown, Takashi Iwai
  Cc: Daniel Mack, Haojian Zhuang, Jaroslav Kysela, Takashi Iwai,
	Liam Girdwood, linux-arm-kernel, linux-kernel, alsa-devel,
	patches

Robert Jarzmik <robert.jarzmik@free.fr> writes:

> It all started in the pxa device-tree submission here :
>    https://lkml.org/lkml/2016/2/25/965
>    
> It will be maintained in :
>    git fetch https://github.com/rjarzmik/linux.git work/ac97
>
> And now it transformed into this RFC, which would bring a ground for AC'97
> devices closer to the linux device/driver model.
>
> The driving ideas are still the same, and I put them in [1] for memory. This is
> the second opus of the RFC. I'm intending to stop the RFC cycle here if possible
> and have a true PATCH v1 submission after this RFC v2 unless there is a deep
> design flaw uncovered.
>
> I took into account Mark's and Takashi's remarks, I hope I forgot none. All the
> changes should be documented in the first 2 patches mainly. I also added :
>  - the AC97 link clock
>    For now, bus code doesn't disable it in suspend and re-enable in resume,
>    leaving the controller decide. I'm still pondering if for S2RAM (as opposed
>    to runtime suspend), bus code should disable the clock.
>
>  - the .h guards
>    I'm not particularly happy with my naming even for v2, feel free to propose
>    anything better, the codec.h is particularly ugly.
>
>  - statics and namespace pollution
>    I made more functions static, limiting further the namespace pollution.
>
>  - Kconfig/Makefile layout change
>    I get the feeling that the KConfig "select" flavor would have better been a
>    "depends on" one. And yet I didn't find a good way to enforce it, because of
>    the way sound/soc/codecs/Kconfig is designed, and I'm afraid to break the
>    structure by doing a "depends on AC97_BUS_NEW" in WM9713 configuration.
>
> Let's have another review cycle, that will let me test this serie more
> thoroughly, especially the suspend/resume and the reset in the resume, which
> doesn't work, and requires me to test more deeply. I'll also test by removing
> the wm9713 change to see how robust the implementation is.

Hi Mark,

It's been some time, and I'm coming back to this work, as my v4l2 work is almost
over.  I made a bit more testing, it doesn't look any worse for pxa + wm9713
couple than before.

I have a new concern with arose with this serie about the wm9713, a trouble in
how the touchscreen wm97xx-ts is probed, ie :
 - drivers/input/touchscreen/wm97xx-core.c, the wm97xx_driver structure

In the old ac97 bus, the match function was always returning "true", and the
driver did probe. With this new implementation, the ac97 is discovered and
sound/soc/codecs/wm9713.c#wm9713_ac97_probe() is called. I don't export
ac97_bus_type (nor want to do it), and only _one_ device is created upon
discovery, while the wm97xx-core.c would benefic a second ac97 device.

I'm wondering how to work around this :
 - either I add a wm97xx-ts ac97 device in wm9713_ac97_probe()
 - or I add a platform device in wm9713_ac97_probe() and add a new
   platform_driver in wm97xx-core ...
 - or something smarter

What's behind this question is : should I keep to my initial solution of 1 ac97
device discovered is bound on the ac97 to _at most_ 1 ac97 driver, or is there a
know smart way to have several drivers for one device (that sounds a bit heretic
regarding my understanding of the device/driver model but who knows ...) ?

Cheers.

--
Robert

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH v2 0/7] AC97 device/driver model revamp
  2016-08-23 16:39 ` [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
@ 2016-08-24 11:39   ` Mark Brown
  2016-08-29  7:49     ` Robert Jarzmik
  0 siblings, 1 reply; 11+ messages in thread
From: Mark Brown @ 2016-08-24 11:39 UTC (permalink / raw)
  To: Robert Jarzmik
  Cc: Takashi Iwai, Daniel Mack, Haojian Zhuang, Jaroslav Kysela,
	Liam Girdwood, linux-arm-kernel, linux-kernel, alsa-devel,
	patches

[-- Attachment #1: Type: text/plain, Size: 1098 bytes --]

On Tue, Aug 23, 2016 at 06:39:35PM +0200, Robert Jarzmik wrote:

> In the old ac97 bus, the match function was always returning "true", and the
> driver did probe. With this new implementation, the ac97 is discovered and
> sound/soc/codecs/wm9713.c#wm9713_ac97_probe() is called. I don't export
> ac97_bus_type (nor want to do it), and only _one_ device is created upon
> discovery, while the wm97xx-core.c would benefic a second ac97 device.

> I'm wondering how to work around this :
>  - either I add a wm97xx-ts ac97 device in wm9713_ac97_probe()
>  - or I add a platform device in wm9713_ac97_probe() and add a new
>    platform_driver in wm97xx-core ...
>  - or something smarter

That device really should be a MFD.

> What's behind this question is : should I keep to my initial solution of 1 ac97
> device discovered is bound on the ac97 to _at most_ 1 ac97 driver, or is there a
> know smart way to have several drivers for one device (that sounds a bit heretic
> regarding my understanding of the device/driver model but who knows ...) ?

MFDs are how we do multiple drivers per device.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH v2 0/7] AC97 device/driver model revamp
  2016-08-24 11:39   ` Mark Brown
@ 2016-08-29  7:49     ` Robert Jarzmik
  0 siblings, 0 replies; 11+ messages in thread
From: Robert Jarzmik @ 2016-08-29  7:49 UTC (permalink / raw)
  To: Mark Brown
  Cc: Takashi Iwai, Daniel Mack, Haojian Zhuang, Jaroslav Kysela,
	Liam Girdwood, linux-arm-kernel, linux-kernel, alsa-devel,
	patches

Mark Brown <broonie@kernel.org> writes:

> On Tue, Aug 23, 2016 at 06:39:35PM +0200, Robert Jarzmik wrote:
>
>> In the old ac97 bus, the match function was always returning "true", and the
>> driver did probe. With this new implementation, the ac97 is discovered and
>> sound/soc/codecs/wm9713.c#wm9713_ac97_probe() is called. I don't export
>> ac97_bus_type (nor want to do it), and only _one_ device is created upon
>> discovery, while the wm97xx-core.c would benefic a second ac97 device.
>
>> I'm wondering how to work around this :
>>  - either I add a wm97xx-ts ac97 device in wm9713_ac97_probe()
>>  - or I add a platform device in wm9713_ac97_probe() and add a new
>>    platform_driver in wm97xx-core ...
>>  - or something smarter
>
> That device really should be a MFD.
>
>> What's behind this question is : should I keep to my initial solution of 1 ac97
>> device discovered is bound on the ac97 to _at most_ 1 ac97 driver, or is there a
>> know smart way to have several drivers for one device (that sounds a bit heretic
>> regarding my understanding of the device/driver model but who knows ...) ?
>
> MFDs are how we do multiple drivers per device.

Ok Mark, I took the bait and implemented it in
https://github.com/rjarzmik/linux/commits/work/ac97, and more specifically in :
  https://github.com/rjarzmik/linux/commit/4689ab3085b6e3959c873b4aa6dc4bc94ca5fd5c
  https://github.com/rjarzmik/linux/commit/152d57d535070871e401fab512b9babdcda9a545
  https://github.com/rjarzmik/linux/commit/903569ff077d1ea992dfc69d2f3014ce0d10fa99

I didn't send the patches for review yet as I face another kind of problem.
I converted wm9713 to an mfd device :
 - with a core in drivers/mfd
 - a codec in drivers/sound/soc/codec
 - a touchscreen in drivers/input/touchscreen
 - a battery in drivers/power/

The remaining problem is the lack of possibility to "customize" through
platform_data, which impact wm97xx_battery.c.
The reason of this is that :
 - the core in driver/mfd is "autoprobed" by the ac97 discovery mecanism
   As such, it has no platform data
 - the battery in drivers/power/wm97xx_battery.c will have its device spawned
   from the core and any platform data from it.

As you probably know wm97xx_battery needs platform data to be properly set up,
and unless I add a special "glue" in the ac97 device to provide this data I see
no other option. Would you think of something better ?

Actually the wm97xx could be even further improved by "offering" an ADC API the
battery driver could be bound to and consume just as regulators are, but that's
probably not worth it for only one old driver.

I'll post the serie within this week.

-- 
Robert

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2016-08-29  7:49 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-27 20:26 [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
2016-05-27 20:26 ` [RFC PATCH v2 1/7] ALSA: ac97: split out the generic ac97 registers Robert Jarzmik
2016-05-27 20:26 ` [RFC PATCH v2 2/7] ALSA: ac97: add an ac97 bus Robert Jarzmik
2016-05-27 20:26 ` [RFC PATCH v2 3/7] ASoC: add new ac97 bus support Robert Jarzmik
2016-05-27 20:26 ` [RFC PATCH v2 4/7] ASoC: wm9713: add ac97 new " Robert Jarzmik
2016-05-27 20:26 ` [RFC PATCH v2 5/7] ASoC: pxa: switch to new ac97 " Robert Jarzmik
2016-05-27 20:26 ` [RFC PATCH v2 6/7] ARM: pxa: mioa701 convert to the new AC97 bus Robert Jarzmik
2016-05-27 20:26 ` [RFC PATCH v2 7/7] ASoC: mioa701_wm9713: convert to new ac97 bus Robert Jarzmik
2016-08-23 16:39 ` [RFC PATCH v2 0/7] AC97 device/driver model revamp Robert Jarzmik
2016-08-24 11:39   ` Mark Brown
2016-08-29  7:49     ` Robert Jarzmik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).