1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Asihpi soundcard
4*4882a593Smuzhiyun * Copyright (c) by AudioScience Inc <support@audioscience.com>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * The following is not a condition of use, merely a request:
7*4882a593Smuzhiyun * If you modify this program, particularly if you fix errors, AudioScience Inc
8*4882a593Smuzhiyun * would appreciate it if you grant us the right to use those modifications
9*4882a593Smuzhiyun * for any purpose including commercial applications.
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include "hpi_internal.h"
13*4882a593Smuzhiyun #include "hpi_version.h"
14*4882a593Smuzhiyun #include "hpimsginit.h"
15*4882a593Smuzhiyun #include "hpioctl.h"
16*4882a593Smuzhiyun #include "hpicmn.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <linux/pci.h>
19*4882a593Smuzhiyun #include <linux/init.h>
20*4882a593Smuzhiyun #include <linux/jiffies.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun #include <linux/time.h>
23*4882a593Smuzhiyun #include <linux/wait.h>
24*4882a593Smuzhiyun #include <linux/module.h>
25*4882a593Smuzhiyun #include <sound/core.h>
26*4882a593Smuzhiyun #include <sound/control.h>
27*4882a593Smuzhiyun #include <sound/pcm.h>
28*4882a593Smuzhiyun #include <sound/pcm_params.h>
29*4882a593Smuzhiyun #include <sound/info.h>
30*4882a593Smuzhiyun #include <sound/initval.h>
31*4882a593Smuzhiyun #include <sound/tlv.h>
32*4882a593Smuzhiyun #include <sound/hwdep.h>
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun MODULE_LICENSE("GPL");
35*4882a593Smuzhiyun MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
36*4882a593Smuzhiyun MODULE_DESCRIPTION("AudioScience ALSA ASI5xxx ASI6xxx ASI87xx ASI89xx "
37*4882a593Smuzhiyun HPI_VER_STRING);
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #if defined CONFIG_SND_DEBUG_VERBOSE
40*4882a593Smuzhiyun /**
41*4882a593Smuzhiyun * snd_printddd - very verbose debug printk
42*4882a593Smuzhiyun * @format: format string
43*4882a593Smuzhiyun *
44*4882a593Smuzhiyun * Works like snd_printk() for debugging purposes.
45*4882a593Smuzhiyun * Ignored when CONFIG_SND_DEBUG_VERBOSE is not set.
46*4882a593Smuzhiyun * Must set snd module debug parameter to 3 to enable at runtime.
47*4882a593Smuzhiyun */
48*4882a593Smuzhiyun #define snd_printddd(format, args...) \
49*4882a593Smuzhiyun __snd_printk(3, __FILE__, __LINE__, format, ##args)
50*4882a593Smuzhiyun #else
51*4882a593Smuzhiyun #define snd_printddd(format, args...) do { } while (0)
52*4882a593Smuzhiyun #endif
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */
55*4882a593Smuzhiyun static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
56*4882a593Smuzhiyun static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
57*4882a593Smuzhiyun static bool enable_hpi_hwdep = 1;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun module_param_array(index, int, NULL, 0444);
60*4882a593Smuzhiyun MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard.");
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun module_param_array(id, charp, NULL, 0444);
63*4882a593Smuzhiyun MODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard.");
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun module_param_array(enable, bool, NULL, 0444);
66*4882a593Smuzhiyun MODULE_PARM_DESC(enable, "ALSA enable AudioScience soundcard.");
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun module_param(enable_hpi_hwdep, bool, 0644);
69*4882a593Smuzhiyun MODULE_PARM_DESC(enable_hpi_hwdep,
70*4882a593Smuzhiyun "ALSA enable HPI hwdep for AudioScience soundcard ");
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* identify driver */
73*4882a593Smuzhiyun #ifdef KERNEL_ALSA_BUILD
74*4882a593Smuzhiyun static char *build_info = "Built using headers from kernel source";
75*4882a593Smuzhiyun module_param(build_info, charp, 0444);
76*4882a593Smuzhiyun MODULE_PARM_DESC(build_info, "Built using headers from kernel source");
77*4882a593Smuzhiyun #else
78*4882a593Smuzhiyun static char *build_info = "Built within ALSA source";
79*4882a593Smuzhiyun module_param(build_info, charp, 0444);
80*4882a593Smuzhiyun MODULE_PARM_DESC(build_info, "Built within ALSA source");
81*4882a593Smuzhiyun #endif
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /* set to 1 to dump every control from adapter to log */
84*4882a593Smuzhiyun static const int mixer_dump;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun #define DEFAULT_SAMPLERATE 44100
87*4882a593Smuzhiyun static int adapter_fs = DEFAULT_SAMPLERATE;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* defaults */
90*4882a593Smuzhiyun #define PERIODS_MIN 2
91*4882a593Smuzhiyun #define PERIOD_BYTES_MIN 2048
92*4882a593Smuzhiyun #define BUFFER_BYTES_MAX (512 * 1024)
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun #define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun struct clk_source {
97*4882a593Smuzhiyun int source;
98*4882a593Smuzhiyun int index;
99*4882a593Smuzhiyun const char *name;
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun struct clk_cache {
103*4882a593Smuzhiyun int count;
104*4882a593Smuzhiyun int has_local;
105*4882a593Smuzhiyun struct clk_source s[MAX_CLOCKSOURCES];
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* Per card data */
109*4882a593Smuzhiyun struct snd_card_asihpi {
110*4882a593Smuzhiyun struct snd_card *card;
111*4882a593Smuzhiyun struct pci_dev *pci;
112*4882a593Smuzhiyun struct hpi_adapter *hpi;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun /* In low latency mode there is only one stream, a pointer to its
115*4882a593Smuzhiyun * private data is stored here on trigger and cleared on stop.
116*4882a593Smuzhiyun * The interrupt handler uses it as a parameter when calling
117*4882a593Smuzhiyun * snd_card_asihpi_timer_function().
118*4882a593Smuzhiyun */
119*4882a593Smuzhiyun struct snd_card_asihpi_pcm *llmode_streampriv;
120*4882a593Smuzhiyun void (*pcm_start)(struct snd_pcm_substream *substream);
121*4882a593Smuzhiyun void (*pcm_stop)(struct snd_pcm_substream *substream);
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun u32 h_mixer;
124*4882a593Smuzhiyun struct clk_cache cc;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun u16 can_dma;
127*4882a593Smuzhiyun u16 support_grouping;
128*4882a593Smuzhiyun u16 support_mrx;
129*4882a593Smuzhiyun u16 update_interval_frames;
130*4882a593Smuzhiyun u16 in_max_chans;
131*4882a593Smuzhiyun u16 out_max_chans;
132*4882a593Smuzhiyun u16 in_min_chans;
133*4882a593Smuzhiyun u16 out_min_chans;
134*4882a593Smuzhiyun };
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /* Per stream data */
137*4882a593Smuzhiyun struct snd_card_asihpi_pcm {
138*4882a593Smuzhiyun struct timer_list timer;
139*4882a593Smuzhiyun unsigned int respawn_timer;
140*4882a593Smuzhiyun unsigned int hpi_buffer_attached;
141*4882a593Smuzhiyun unsigned int buffer_bytes;
142*4882a593Smuzhiyun unsigned int period_bytes;
143*4882a593Smuzhiyun unsigned int bytes_per_sec;
144*4882a593Smuzhiyun unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */
145*4882a593Smuzhiyun unsigned int pcm_buf_dma_ofs; /* DMA R/W offset in buffer */
146*4882a593Smuzhiyun unsigned int pcm_buf_elapsed_dma_ofs; /* DMA R/W offset in buffer */
147*4882a593Smuzhiyun unsigned int drained_count;
148*4882a593Smuzhiyun struct snd_pcm_substream *substream;
149*4882a593Smuzhiyun u32 h_stream;
150*4882a593Smuzhiyun struct hpi_format format;
151*4882a593Smuzhiyun };
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun /* universal stream verbs work with out or in stream handles */
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun /* Functions to allow driver to give a buffer to HPI for busmastering */
156*4882a593Smuzhiyun
hpi_stream_host_buffer_attach(u32 h_stream,u32 size_in_bytes,u32 pci_address)157*4882a593Smuzhiyun static u16 hpi_stream_host_buffer_attach(
158*4882a593Smuzhiyun u32 h_stream, /* handle to outstream. */
159*4882a593Smuzhiyun u32 size_in_bytes, /* size in bytes of bus mastering buffer */
160*4882a593Smuzhiyun u32 pci_address
161*4882a593Smuzhiyun )
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun struct hpi_message hm;
164*4882a593Smuzhiyun struct hpi_response hr;
165*4882a593Smuzhiyun unsigned int obj = hpi_handle_object(h_stream);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun if (!h_stream)
168*4882a593Smuzhiyun return HPI_ERROR_INVALID_OBJ;
169*4882a593Smuzhiyun hpi_init_message_response(&hm, &hr, obj,
170*4882a593Smuzhiyun obj == HPI_OBJ_OSTREAM ?
171*4882a593Smuzhiyun HPI_OSTREAM_HOSTBUFFER_ALLOC :
172*4882a593Smuzhiyun HPI_ISTREAM_HOSTBUFFER_ALLOC);
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun hpi_handle_to_indexes(h_stream, &hm.adapter_index,
175*4882a593Smuzhiyun &hm.obj_index);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun hm.u.d.u.buffer.buffer_size = size_in_bytes;
178*4882a593Smuzhiyun hm.u.d.u.buffer.pci_address = pci_address;
179*4882a593Smuzhiyun hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER;
180*4882a593Smuzhiyun hpi_send_recv(&hm, &hr);
181*4882a593Smuzhiyun return hr.error;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
hpi_stream_host_buffer_detach(u32 h_stream)184*4882a593Smuzhiyun static u16 hpi_stream_host_buffer_detach(u32 h_stream)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun struct hpi_message hm;
187*4882a593Smuzhiyun struct hpi_response hr;
188*4882a593Smuzhiyun unsigned int obj = hpi_handle_object(h_stream);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun if (!h_stream)
191*4882a593Smuzhiyun return HPI_ERROR_INVALID_OBJ;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun hpi_init_message_response(&hm, &hr, obj,
194*4882a593Smuzhiyun obj == HPI_OBJ_OSTREAM ?
195*4882a593Smuzhiyun HPI_OSTREAM_HOSTBUFFER_FREE :
196*4882a593Smuzhiyun HPI_ISTREAM_HOSTBUFFER_FREE);
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun hpi_handle_to_indexes(h_stream, &hm.adapter_index,
199*4882a593Smuzhiyun &hm.obj_index);
200*4882a593Smuzhiyun hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER;
201*4882a593Smuzhiyun hpi_send_recv(&hm, &hr);
202*4882a593Smuzhiyun return hr.error;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
hpi_stream_start(u32 h_stream)205*4882a593Smuzhiyun static inline u16 hpi_stream_start(u32 h_stream)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
208*4882a593Smuzhiyun return hpi_outstream_start(h_stream);
209*4882a593Smuzhiyun else
210*4882a593Smuzhiyun return hpi_instream_start(h_stream);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
hpi_stream_stop(u32 h_stream)213*4882a593Smuzhiyun static inline u16 hpi_stream_stop(u32 h_stream)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
216*4882a593Smuzhiyun return hpi_outstream_stop(h_stream);
217*4882a593Smuzhiyun else
218*4882a593Smuzhiyun return hpi_instream_stop(h_stream);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
hpi_stream_get_info_ex(u32 h_stream,u16 * pw_state,u32 * pbuffer_size,u32 * pdata_in_buffer,u32 * psample_count,u32 * pauxiliary_data)221*4882a593Smuzhiyun static inline u16 hpi_stream_get_info_ex(
222*4882a593Smuzhiyun u32 h_stream,
223*4882a593Smuzhiyun u16 *pw_state,
224*4882a593Smuzhiyun u32 *pbuffer_size,
225*4882a593Smuzhiyun u32 *pdata_in_buffer,
226*4882a593Smuzhiyun u32 *psample_count,
227*4882a593Smuzhiyun u32 *pauxiliary_data
228*4882a593Smuzhiyun )
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun u16 e;
231*4882a593Smuzhiyun if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
232*4882a593Smuzhiyun e = hpi_outstream_get_info_ex(h_stream, pw_state,
233*4882a593Smuzhiyun pbuffer_size, pdata_in_buffer,
234*4882a593Smuzhiyun psample_count, pauxiliary_data);
235*4882a593Smuzhiyun else
236*4882a593Smuzhiyun e = hpi_instream_get_info_ex(h_stream, pw_state,
237*4882a593Smuzhiyun pbuffer_size, pdata_in_buffer,
238*4882a593Smuzhiyun psample_count, pauxiliary_data);
239*4882a593Smuzhiyun return e;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
hpi_stream_group_add(u32 h_master,u32 h_stream)242*4882a593Smuzhiyun static inline u16 hpi_stream_group_add(
243*4882a593Smuzhiyun u32 h_master,
244*4882a593Smuzhiyun u32 h_stream)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun if (hpi_handle_object(h_master) == HPI_OBJ_OSTREAM)
247*4882a593Smuzhiyun return hpi_outstream_group_add(h_master, h_stream);
248*4882a593Smuzhiyun else
249*4882a593Smuzhiyun return hpi_instream_group_add(h_master, h_stream);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
hpi_stream_group_reset(u32 h_stream)252*4882a593Smuzhiyun static inline u16 hpi_stream_group_reset(u32 h_stream)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
255*4882a593Smuzhiyun return hpi_outstream_group_reset(h_stream);
256*4882a593Smuzhiyun else
257*4882a593Smuzhiyun return hpi_instream_group_reset(h_stream);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
handle_error(u16 err,int line,char * filename)260*4882a593Smuzhiyun static u16 handle_error(u16 err, int line, char *filename)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun if (err)
263*4882a593Smuzhiyun printk(KERN_WARNING
264*4882a593Smuzhiyun "in file %s, line %d: HPI error %d\n",
265*4882a593Smuzhiyun filename, line, err);
266*4882a593Smuzhiyun return err;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun #define hpi_handle_error(x) handle_error(x, __LINE__, __FILE__)
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /***************************** GENERAL PCM ****************/
272*4882a593Smuzhiyun
print_hwparams(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * p)273*4882a593Smuzhiyun static void print_hwparams(struct snd_pcm_substream *substream,
274*4882a593Smuzhiyun struct snd_pcm_hw_params *p)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun char name[16];
277*4882a593Smuzhiyun snd_pcm_debug_name(substream, name, sizeof(name));
278*4882a593Smuzhiyun snd_printdd("%s HWPARAMS\n", name);
279*4882a593Smuzhiyun snd_printdd(" samplerate=%dHz channels=%d format=%d subformat=%d\n",
280*4882a593Smuzhiyun params_rate(p), params_channels(p),
281*4882a593Smuzhiyun params_format(p), params_subformat(p));
282*4882a593Smuzhiyun snd_printdd(" buffer=%dB period=%dB period_size=%dB periods=%d\n",
283*4882a593Smuzhiyun params_buffer_bytes(p), params_period_bytes(p),
284*4882a593Smuzhiyun params_period_size(p), params_periods(p));
285*4882a593Smuzhiyun snd_printdd(" buffer_size=%d access=%d data_rate=%dB/s\n",
286*4882a593Smuzhiyun params_buffer_size(p), params_access(p),
287*4882a593Smuzhiyun params_rate(p) * params_channels(p) *
288*4882a593Smuzhiyun snd_pcm_format_width(params_format(p)) / 8);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun #define INVALID_FORMAT (__force snd_pcm_format_t)(-1)
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun static const snd_pcm_format_t hpi_to_alsa_formats[] = {
294*4882a593Smuzhiyun INVALID_FORMAT, /* INVALID */
295*4882a593Smuzhiyun SNDRV_PCM_FORMAT_U8, /* HPI_FORMAT_PCM8_UNSIGNED 1 */
296*4882a593Smuzhiyun SNDRV_PCM_FORMAT_S16, /* HPI_FORMAT_PCM16_SIGNED 2 */
297*4882a593Smuzhiyun INVALID_FORMAT, /* HPI_FORMAT_MPEG_L1 3 */
298*4882a593Smuzhiyun SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L2 4 */
299*4882a593Smuzhiyun SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L3 5 */
300*4882a593Smuzhiyun INVALID_FORMAT, /* HPI_FORMAT_DOLBY_AC2 6 */
301*4882a593Smuzhiyun INVALID_FORMAT, /* HPI_FORMAT_DOLBY_AC3 7 */
302*4882a593Smuzhiyun SNDRV_PCM_FORMAT_S16_BE,/* HPI_FORMAT_PCM16_BIGENDIAN 8 */
303*4882a593Smuzhiyun INVALID_FORMAT, /* HPI_FORMAT_AA_TAGIT1_HITS 9 */
304*4882a593Smuzhiyun INVALID_FORMAT, /* HPI_FORMAT_AA_TAGIT1_INSERTS 10 */
305*4882a593Smuzhiyun SNDRV_PCM_FORMAT_S32, /* HPI_FORMAT_PCM32_SIGNED 11 */
306*4882a593Smuzhiyun INVALID_FORMAT, /* HPI_FORMAT_RAW_BITSTREAM 12 */
307*4882a593Smuzhiyun INVALID_FORMAT, /* HPI_FORMAT_AA_TAGIT1_HITS_EX1 13 */
308*4882a593Smuzhiyun SNDRV_PCM_FORMAT_FLOAT, /* HPI_FORMAT_PCM32_FLOAT 14 */
309*4882a593Smuzhiyun #if 1
310*4882a593Smuzhiyun /* ALSA can't handle 3 byte sample size together with power-of-2
311*4882a593Smuzhiyun * constraint on buffer_bytes, so disable this format
312*4882a593Smuzhiyun */
313*4882a593Smuzhiyun INVALID_FORMAT
314*4882a593Smuzhiyun #else
315*4882a593Smuzhiyun /* SNDRV_PCM_FORMAT_S24_3LE */ /* HPI_FORMAT_PCM24_SIGNED 15 */
316*4882a593Smuzhiyun #endif
317*4882a593Smuzhiyun };
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun
snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format,u16 * hpi_format)320*4882a593Smuzhiyun static int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format,
321*4882a593Smuzhiyun u16 *hpi_format)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun u16 format;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun for (format = HPI_FORMAT_PCM8_UNSIGNED;
326*4882a593Smuzhiyun format <= HPI_FORMAT_PCM24_SIGNED; format++) {
327*4882a593Smuzhiyun if (hpi_to_alsa_formats[format] == alsa_format) {
328*4882a593Smuzhiyun *hpi_format = format;
329*4882a593Smuzhiyun return 0;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun snd_printd(KERN_WARNING "failed match for alsa format %d\n",
334*4882a593Smuzhiyun alsa_format);
335*4882a593Smuzhiyun *hpi_format = 0;
336*4882a593Smuzhiyun return -EINVAL;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi * asihpi,struct snd_pcm_hardware * pcmhw)339*4882a593Smuzhiyun static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi,
340*4882a593Smuzhiyun struct snd_pcm_hardware *pcmhw)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun u16 err;
343*4882a593Smuzhiyun u32 h_control;
344*4882a593Smuzhiyun u32 sample_rate;
345*4882a593Smuzhiyun int idx;
346*4882a593Smuzhiyun unsigned int rate_min = 200000;
347*4882a593Smuzhiyun unsigned int rate_max = 0;
348*4882a593Smuzhiyun unsigned int rates = 0;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun if (asihpi->support_mrx) {
351*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_CONTINUOUS;
352*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_8000_96000;
353*4882a593Smuzhiyun rate_min = 8000;
354*4882a593Smuzhiyun rate_max = 100000;
355*4882a593Smuzhiyun } else {
356*4882a593Smuzhiyun /* on cards without SRC,
357*4882a593Smuzhiyun valid rates are determined by sampleclock */
358*4882a593Smuzhiyun err = hpi_mixer_get_control(asihpi->h_mixer,
359*4882a593Smuzhiyun HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
360*4882a593Smuzhiyun HPI_CONTROL_SAMPLECLOCK, &h_control);
361*4882a593Smuzhiyun if (err) {
362*4882a593Smuzhiyun dev_err(&asihpi->pci->dev,
363*4882a593Smuzhiyun "No local sampleclock, err %d\n", err);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun for (idx = -1; idx < 100; idx++) {
367*4882a593Smuzhiyun if (idx == -1) {
368*4882a593Smuzhiyun if (hpi_sample_clock_get_sample_rate(h_control,
369*4882a593Smuzhiyun &sample_rate))
370*4882a593Smuzhiyun continue;
371*4882a593Smuzhiyun } else if (hpi_sample_clock_query_local_rate(h_control,
372*4882a593Smuzhiyun idx, &sample_rate)) {
373*4882a593Smuzhiyun break;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun rate_min = min(rate_min, sample_rate);
377*4882a593Smuzhiyun rate_max = max(rate_max, sample_rate);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun switch (sample_rate) {
380*4882a593Smuzhiyun case 5512:
381*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_5512;
382*4882a593Smuzhiyun break;
383*4882a593Smuzhiyun case 8000:
384*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_8000;
385*4882a593Smuzhiyun break;
386*4882a593Smuzhiyun case 11025:
387*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_11025;
388*4882a593Smuzhiyun break;
389*4882a593Smuzhiyun case 16000:
390*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_16000;
391*4882a593Smuzhiyun break;
392*4882a593Smuzhiyun case 22050:
393*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_22050;
394*4882a593Smuzhiyun break;
395*4882a593Smuzhiyun case 32000:
396*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_32000;
397*4882a593Smuzhiyun break;
398*4882a593Smuzhiyun case 44100:
399*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_44100;
400*4882a593Smuzhiyun break;
401*4882a593Smuzhiyun case 48000:
402*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_48000;
403*4882a593Smuzhiyun break;
404*4882a593Smuzhiyun case 64000:
405*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_64000;
406*4882a593Smuzhiyun break;
407*4882a593Smuzhiyun case 88200:
408*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_88200;
409*4882a593Smuzhiyun break;
410*4882a593Smuzhiyun case 96000:
411*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_96000;
412*4882a593Smuzhiyun break;
413*4882a593Smuzhiyun case 176400:
414*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_176400;
415*4882a593Smuzhiyun break;
416*4882a593Smuzhiyun case 192000:
417*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_192000;
418*4882a593Smuzhiyun break;
419*4882a593Smuzhiyun default: /* some other rate */
420*4882a593Smuzhiyun rates |= SNDRV_PCM_RATE_KNOT;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun pcmhw->rates = rates;
426*4882a593Smuzhiyun pcmhw->rate_min = rate_min;
427*4882a593Smuzhiyun pcmhw->rate_max = rate_max;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)430*4882a593Smuzhiyun static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
431*4882a593Smuzhiyun struct snd_pcm_hw_params *params)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
434*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
435*4882a593Smuzhiyun struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
436*4882a593Smuzhiyun int err;
437*4882a593Smuzhiyun u16 format;
438*4882a593Smuzhiyun int width;
439*4882a593Smuzhiyun unsigned int bytes_per_sec;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun print_hwparams(substream, params);
442*4882a593Smuzhiyun err = snd_card_asihpi_format_alsa2hpi(params_format(params), &format);
443*4882a593Smuzhiyun if (err)
444*4882a593Smuzhiyun return err;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun hpi_handle_error(hpi_format_create(&dpcm->format,
447*4882a593Smuzhiyun params_channels(params),
448*4882a593Smuzhiyun format, params_rate(params), 0, 0));
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
451*4882a593Smuzhiyun if (hpi_instream_reset(dpcm->h_stream) != 0)
452*4882a593Smuzhiyun return -EINVAL;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun if (hpi_instream_set_format(
455*4882a593Smuzhiyun dpcm->h_stream, &dpcm->format) != 0)
456*4882a593Smuzhiyun return -EINVAL;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun dpcm->hpi_buffer_attached = 0;
460*4882a593Smuzhiyun if (card->can_dma) {
461*4882a593Smuzhiyun err = hpi_stream_host_buffer_attach(dpcm->h_stream,
462*4882a593Smuzhiyun params_buffer_bytes(params), runtime->dma_addr);
463*4882a593Smuzhiyun if (err == 0) {
464*4882a593Smuzhiyun snd_printdd(
465*4882a593Smuzhiyun "stream_host_buffer_attach success %u %lu\n",
466*4882a593Smuzhiyun params_buffer_bytes(params),
467*4882a593Smuzhiyun (unsigned long)runtime->dma_addr);
468*4882a593Smuzhiyun } else {
469*4882a593Smuzhiyun snd_printd("stream_host_buffer_attach error %d\n",
470*4882a593Smuzhiyun err);
471*4882a593Smuzhiyun return -ENOMEM;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,
475*4882a593Smuzhiyun &dpcm->hpi_buffer_attached, NULL, NULL, NULL);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun bytes_per_sec = params_rate(params) * params_channels(params);
478*4882a593Smuzhiyun width = snd_pcm_format_width(params_format(params));
479*4882a593Smuzhiyun bytes_per_sec *= width;
480*4882a593Smuzhiyun bytes_per_sec /= 8;
481*4882a593Smuzhiyun if (width < 0 || bytes_per_sec == 0)
482*4882a593Smuzhiyun return -EINVAL;
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun dpcm->bytes_per_sec = bytes_per_sec;
485*4882a593Smuzhiyun dpcm->buffer_bytes = params_buffer_bytes(params);
486*4882a593Smuzhiyun dpcm->period_bytes = params_period_bytes(params);
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun return 0;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun static int
snd_card_asihpi_hw_free(struct snd_pcm_substream * substream)492*4882a593Smuzhiyun snd_card_asihpi_hw_free(struct snd_pcm_substream *substream)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
495*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
496*4882a593Smuzhiyun if (dpcm->hpi_buffer_attached)
497*4882a593Smuzhiyun hpi_stream_host_buffer_detach(dpcm->h_stream);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return 0;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
snd_card_asihpi_runtime_free(struct snd_pcm_runtime * runtime)502*4882a593Smuzhiyun static void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
505*4882a593Smuzhiyun kfree(dpcm);
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream * substream)508*4882a593Smuzhiyun static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
509*4882a593Smuzhiyun substream)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
512*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
513*4882a593Smuzhiyun int expiry;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun expiry = HZ / 200;
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun expiry = max(expiry, 1); /* don't let it be zero! */
518*4882a593Smuzhiyun mod_timer(&dpcm->timer, jiffies + expiry);
519*4882a593Smuzhiyun dpcm->respawn_timer = 1;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream * substream)522*4882a593Smuzhiyun static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
525*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun dpcm->respawn_timer = 0;
528*4882a593Smuzhiyun del_timer(&dpcm->timer);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
snd_card_asihpi_pcm_int_start(struct snd_pcm_substream * substream)531*4882a593Smuzhiyun static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm;
534*4882a593Smuzhiyun struct snd_card_asihpi *card;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data;
537*4882a593Smuzhiyun card = snd_pcm_substream_chip(substream);
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun WARN_ON(in_interrupt());
540*4882a593Smuzhiyun card->llmode_streampriv = dpcm;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index,
543*4882a593Smuzhiyun HPI_ADAPTER_PROPERTY_IRQ_RATE,
544*4882a593Smuzhiyun card->update_interval_frames, 0));
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream * substream)547*4882a593Smuzhiyun static void snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream *substream)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun struct snd_card_asihpi *card;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun card = snd_pcm_substream_chip(substream);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index,
554*4882a593Smuzhiyun HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0));
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun card->llmode_streampriv = NULL;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
snd_card_asihpi_trigger(struct snd_pcm_substream * substream,int cmd)559*4882a593Smuzhiyun static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
560*4882a593Smuzhiyun int cmd)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
563*4882a593Smuzhiyun struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
564*4882a593Smuzhiyun struct snd_pcm_substream *s;
565*4882a593Smuzhiyun u16 e;
566*4882a593Smuzhiyun char name[16];
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun snd_pcm_debug_name(substream, name, sizeof(name));
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun switch (cmd) {
571*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_START:
572*4882a593Smuzhiyun snd_printdd("%s trigger start\n", name);
573*4882a593Smuzhiyun snd_pcm_group_for_each_entry(s, substream) {
574*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = s->runtime;
575*4882a593Smuzhiyun struct snd_card_asihpi_pcm *ds = runtime->private_data;
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun if (snd_pcm_substream_chip(s) != card)
578*4882a593Smuzhiyun continue;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun /* don't link Cap and Play */
581*4882a593Smuzhiyun if (substream->stream != s->stream)
582*4882a593Smuzhiyun continue;
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun ds->drained_count = 0;
585*4882a593Smuzhiyun if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
586*4882a593Smuzhiyun /* How do I know how much valid data is present
587*4882a593Smuzhiyun * in buffer? Must be at least one period!
588*4882a593Smuzhiyun * Guessing 2 periods, but if
589*4882a593Smuzhiyun * buffer is bigger it may contain even more
590*4882a593Smuzhiyun * data??
591*4882a593Smuzhiyun */
592*4882a593Smuzhiyun unsigned int preload = ds->period_bytes * 1;
593*4882a593Smuzhiyun snd_printddd("%d preload %d\n", s->number, preload);
594*4882a593Smuzhiyun hpi_handle_error(hpi_outstream_write_buf(
595*4882a593Smuzhiyun ds->h_stream,
596*4882a593Smuzhiyun &runtime->dma_area[0],
597*4882a593Smuzhiyun preload,
598*4882a593Smuzhiyun &ds->format));
599*4882a593Smuzhiyun ds->pcm_buf_host_rw_ofs = preload;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun if (card->support_grouping) {
603*4882a593Smuzhiyun snd_printdd("%d group\n", s->number);
604*4882a593Smuzhiyun e = hpi_stream_group_add(
605*4882a593Smuzhiyun dpcm->h_stream,
606*4882a593Smuzhiyun ds->h_stream);
607*4882a593Smuzhiyun if (!e) {
608*4882a593Smuzhiyun snd_pcm_trigger_done(s, substream);
609*4882a593Smuzhiyun } else {
610*4882a593Smuzhiyun hpi_handle_error(e);
611*4882a593Smuzhiyun break;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun } else
614*4882a593Smuzhiyun break;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun /* start the master stream */
617*4882a593Smuzhiyun card->pcm_start(substream);
618*4882a593Smuzhiyun if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
619*4882a593Smuzhiyun !card->can_dma)
620*4882a593Smuzhiyun hpi_handle_error(hpi_stream_start(dpcm->h_stream));
621*4882a593Smuzhiyun break;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_STOP:
624*4882a593Smuzhiyun snd_printdd("%s trigger stop\n", name);
625*4882a593Smuzhiyun card->pcm_stop(substream);
626*4882a593Smuzhiyun snd_pcm_group_for_each_entry(s, substream) {
627*4882a593Smuzhiyun if (snd_pcm_substream_chip(s) != card)
628*4882a593Smuzhiyun continue;
629*4882a593Smuzhiyun /* don't link Cap and Play */
630*4882a593Smuzhiyun if (substream->stream != s->stream)
631*4882a593Smuzhiyun continue;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun /*? workaround linked streams don't
634*4882a593Smuzhiyun transition to SETUP 20070706*/
635*4882a593Smuzhiyun s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun if (card->support_grouping) {
638*4882a593Smuzhiyun snd_printdd("%d group\n", s->number);
639*4882a593Smuzhiyun snd_pcm_trigger_done(s, substream);
640*4882a593Smuzhiyun } else
641*4882a593Smuzhiyun break;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun /* _prepare and _hwparams reset the stream */
645*4882a593Smuzhiyun hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
646*4882a593Smuzhiyun if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
647*4882a593Smuzhiyun hpi_handle_error(
648*4882a593Smuzhiyun hpi_outstream_reset(dpcm->h_stream));
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun if (card->support_grouping)
651*4882a593Smuzhiyun hpi_handle_error(hpi_stream_group_reset(dpcm->h_stream));
652*4882a593Smuzhiyun break;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
655*4882a593Smuzhiyun snd_printdd("%s trigger pause release\n", name);
656*4882a593Smuzhiyun card->pcm_start(substream);
657*4882a593Smuzhiyun hpi_handle_error(hpi_stream_start(dpcm->h_stream));
658*4882a593Smuzhiyun break;
659*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
660*4882a593Smuzhiyun snd_printdd("%s trigger pause push\n", name);
661*4882a593Smuzhiyun card->pcm_stop(substream);
662*4882a593Smuzhiyun hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
663*4882a593Smuzhiyun break;
664*4882a593Smuzhiyun default:
665*4882a593Smuzhiyun snd_printd(KERN_ERR "\tINVALID\n");
666*4882a593Smuzhiyun return -EINVAL;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun return 0;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun /*algorithm outline
673*4882a593Smuzhiyun Without linking degenerates to getting single stream pos etc
674*4882a593Smuzhiyun Without mmap 2nd loop degenerates to snd_pcm_period_elapsed
675*4882a593Smuzhiyun */
676*4882a593Smuzhiyun /*
677*4882a593Smuzhiyun pcm_buf_dma_ofs=get_buf_pos(s);
678*4882a593Smuzhiyun for_each_linked_stream(s) {
679*4882a593Smuzhiyun pcm_buf_dma_ofs=get_buf_pos(s);
680*4882a593Smuzhiyun min_buf_pos = modulo_min(min_buf_pos, pcm_buf_dma_ofs, buffer_bytes)
681*4882a593Smuzhiyun new_data = min(new_data, calc_new_data(pcm_buf_dma_ofs,irq_pos)
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun timer.expires = jiffies + predict_next_period_ready(min_buf_pos);
684*4882a593Smuzhiyun for_each_linked_stream(s) {
685*4882a593Smuzhiyun s->pcm_buf_dma_ofs = min_buf_pos;
686*4882a593Smuzhiyun if (new_data > period_bytes) {
687*4882a593Smuzhiyun if (mmap) {
688*4882a593Smuzhiyun irq_pos = (irq_pos + period_bytes) % buffer_bytes;
689*4882a593Smuzhiyun if (playback) {
690*4882a593Smuzhiyun write(period_bytes);
691*4882a593Smuzhiyun } else {
692*4882a593Smuzhiyun read(period_bytes);
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun snd_pcm_period_elapsed(s);
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun */
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun /** Minimum of 2 modulo values. Works correctly when the difference between
701*4882a593Smuzhiyun * the values is less than half the modulus
702*4882a593Smuzhiyun */
modulo_min(unsigned int a,unsigned int b,unsigned long int modulus)703*4882a593Smuzhiyun static inline unsigned int modulo_min(unsigned int a, unsigned int b,
704*4882a593Smuzhiyun unsigned long int modulus)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun unsigned int result;
707*4882a593Smuzhiyun if (((a-b) % modulus) < (modulus/2))
708*4882a593Smuzhiyun result = b;
709*4882a593Smuzhiyun else
710*4882a593Smuzhiyun result = a;
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun return result;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun /** Timer function, equivalent to interrupt service routine for cards
716*4882a593Smuzhiyun */
snd_card_asihpi_timer_function(struct timer_list * t)717*4882a593Smuzhiyun static void snd_card_asihpi_timer_function(struct timer_list *t)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = from_timer(dpcm, t, timer);
720*4882a593Smuzhiyun struct snd_pcm_substream *substream = dpcm->substream;
721*4882a593Smuzhiyun struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
722*4882a593Smuzhiyun struct snd_pcm_runtime *runtime;
723*4882a593Smuzhiyun struct snd_pcm_substream *s;
724*4882a593Smuzhiyun unsigned int newdata = 0;
725*4882a593Smuzhiyun unsigned int pcm_buf_dma_ofs, min_buf_pos = 0;
726*4882a593Smuzhiyun unsigned int remdata, xfercount, next_jiffies;
727*4882a593Smuzhiyun int first = 1;
728*4882a593Smuzhiyun int loops = 0;
729*4882a593Smuzhiyun u16 state;
730*4882a593Smuzhiyun u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
731*4882a593Smuzhiyun char name[16];
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun snd_pcm_debug_name(substream, name, sizeof(name));
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun /* find minimum newdata and buffer pos in group */
737*4882a593Smuzhiyun snd_pcm_group_for_each_entry(s, substream) {
738*4882a593Smuzhiyun struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
739*4882a593Smuzhiyun runtime = s->runtime;
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun if (snd_pcm_substream_chip(s) != card)
742*4882a593Smuzhiyun continue;
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun /* don't link Cap and Play */
745*4882a593Smuzhiyun if (substream->stream != s->stream)
746*4882a593Smuzhiyun continue;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun hpi_handle_error(hpi_stream_get_info_ex(
749*4882a593Smuzhiyun ds->h_stream, &state,
750*4882a593Smuzhiyun &buffer_size, &bytes_avail,
751*4882a593Smuzhiyun &samples_played, &on_card_bytes));
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun /* number of bytes in on-card buffer */
754*4882a593Smuzhiyun runtime->delay = on_card_bytes;
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun if (!card->can_dma)
757*4882a593Smuzhiyun on_card_bytes = bytes_avail;
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
760*4882a593Smuzhiyun pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
761*4882a593Smuzhiyun if (state == HPI_STATE_STOPPED) {
762*4882a593Smuzhiyun if (bytes_avail == 0) {
763*4882a593Smuzhiyun hpi_handle_error(hpi_stream_start(ds->h_stream));
764*4882a593Smuzhiyun snd_printdd("P%d start\n", s->number);
765*4882a593Smuzhiyun ds->drained_count = 0;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun } else if (state == HPI_STATE_DRAINED) {
768*4882a593Smuzhiyun snd_printd(KERN_WARNING "P%d drained\n",
769*4882a593Smuzhiyun s->number);
770*4882a593Smuzhiyun ds->drained_count++;
771*4882a593Smuzhiyun if (ds->drained_count > 20) {
772*4882a593Smuzhiyun snd_pcm_stop_xrun(s);
773*4882a593Smuzhiyun continue;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun } else {
776*4882a593Smuzhiyun ds->drained_count = 0;
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun } else
779*4882a593Smuzhiyun pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun if (first) {
782*4882a593Smuzhiyun /* can't statically init min when wrap is involved */
783*4882a593Smuzhiyun min_buf_pos = pcm_buf_dma_ofs;
784*4882a593Smuzhiyun newdata = (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes;
785*4882a593Smuzhiyun first = 0;
786*4882a593Smuzhiyun } else {
787*4882a593Smuzhiyun min_buf_pos =
788*4882a593Smuzhiyun modulo_min(min_buf_pos, pcm_buf_dma_ofs, UINT_MAX+1L);
789*4882a593Smuzhiyun newdata = min(
790*4882a593Smuzhiyun (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes,
791*4882a593Smuzhiyun newdata);
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun snd_printddd(
795*4882a593Smuzhiyun "timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n",
796*4882a593Smuzhiyun name, s->number, state,
797*4882a593Smuzhiyun ds->pcm_buf_elapsed_dma_ofs,
798*4882a593Smuzhiyun ds->pcm_buf_host_rw_ofs,
799*4882a593Smuzhiyun pcm_buf_dma_ofs,
800*4882a593Smuzhiyun (int)bytes_avail,
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun (int)on_card_bytes,
803*4882a593Smuzhiyun buffer_size-bytes_avail,
804*4882a593Smuzhiyun (unsigned long)frames_to_bytes(runtime,
805*4882a593Smuzhiyun runtime->status->hw_ptr),
806*4882a593Smuzhiyun (unsigned long)frames_to_bytes(runtime,
807*4882a593Smuzhiyun runtime->control->appl_ptr)
808*4882a593Smuzhiyun );
809*4882a593Smuzhiyun loops++;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun pcm_buf_dma_ofs = min_buf_pos;
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun remdata = newdata % dpcm->period_bytes;
814*4882a593Smuzhiyun xfercount = newdata - remdata; /* a multiple of period_bytes */
815*4882a593Smuzhiyun /* come back when on_card_bytes has decreased enough to allow
816*4882a593Smuzhiyun write to happen, or when data has been consumed to make another
817*4882a593Smuzhiyun period
818*4882a593Smuzhiyun */
819*4882a593Smuzhiyun if (xfercount && (on_card_bytes > dpcm->period_bytes))
820*4882a593Smuzhiyun next_jiffies = ((on_card_bytes - dpcm->period_bytes) * HZ / dpcm->bytes_per_sec);
821*4882a593Smuzhiyun else
822*4882a593Smuzhiyun next_jiffies = ((dpcm->period_bytes - remdata) * HZ / dpcm->bytes_per_sec);
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun next_jiffies = max(next_jiffies, 1U);
825*4882a593Smuzhiyun dpcm->timer.expires = jiffies + next_jiffies;
826*4882a593Smuzhiyun snd_printddd("timer2, jif=%d, buf_pos=%d, newdata=%d, xfer=%d\n",
827*4882a593Smuzhiyun next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun snd_pcm_group_for_each_entry(s, substream) {
830*4882a593Smuzhiyun struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun /* don't link Cap and Play */
833*4882a593Smuzhiyun if (substream->stream != s->stream)
834*4882a593Smuzhiyun continue;
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun /* Store dma offset for use by pointer callback */
837*4882a593Smuzhiyun ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun if (xfercount &&
840*4882a593Smuzhiyun /* Limit use of on card fifo for playback */
841*4882a593Smuzhiyun ((on_card_bytes <= ds->period_bytes) ||
842*4882a593Smuzhiyun (s->stream == SNDRV_PCM_STREAM_CAPTURE)))
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun unsigned int buf_ofs = ds->pcm_buf_host_rw_ofs % ds->buffer_bytes;
847*4882a593Smuzhiyun unsigned int xfer1, xfer2;
848*4882a593Smuzhiyun char *pd = &s->runtime->dma_area[buf_ofs];
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun if (card->can_dma) { /* buffer wrap is handled at lower level */
851*4882a593Smuzhiyun xfer1 = xfercount;
852*4882a593Smuzhiyun xfer2 = 0;
853*4882a593Smuzhiyun } else {
854*4882a593Smuzhiyun xfer1 = min(xfercount, ds->buffer_bytes - buf_ofs);
855*4882a593Smuzhiyun xfer2 = xfercount - xfer1;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
859*4882a593Smuzhiyun snd_printddd("write1, P=%d, xfer=%d, buf_ofs=%d\n",
860*4882a593Smuzhiyun s->number, xfer1, buf_ofs);
861*4882a593Smuzhiyun hpi_handle_error(
862*4882a593Smuzhiyun hpi_outstream_write_buf(
863*4882a593Smuzhiyun ds->h_stream, pd, xfer1,
864*4882a593Smuzhiyun &ds->format));
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun if (xfer2) {
867*4882a593Smuzhiyun pd = s->runtime->dma_area;
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun snd_printddd("write2, P=%d, xfer=%d, buf_ofs=%d\n",
870*4882a593Smuzhiyun s->number,
871*4882a593Smuzhiyun xfercount - xfer1, buf_ofs);
872*4882a593Smuzhiyun hpi_handle_error(
873*4882a593Smuzhiyun hpi_outstream_write_buf(
874*4882a593Smuzhiyun ds->h_stream, pd,
875*4882a593Smuzhiyun xfercount - xfer1,
876*4882a593Smuzhiyun &ds->format));
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun } else {
879*4882a593Smuzhiyun snd_printddd("read1, C=%d, xfer=%d\n",
880*4882a593Smuzhiyun s->number, xfer1);
881*4882a593Smuzhiyun hpi_handle_error(
882*4882a593Smuzhiyun hpi_instream_read_buf(
883*4882a593Smuzhiyun ds->h_stream,
884*4882a593Smuzhiyun pd, xfer1));
885*4882a593Smuzhiyun if (xfer2) {
886*4882a593Smuzhiyun pd = s->runtime->dma_area;
887*4882a593Smuzhiyun snd_printddd("read2, C=%d, xfer=%d\n",
888*4882a593Smuzhiyun s->number, xfer2);
889*4882a593Smuzhiyun hpi_handle_error(
890*4882a593Smuzhiyun hpi_instream_read_buf(
891*4882a593Smuzhiyun ds->h_stream,
892*4882a593Smuzhiyun pd, xfer2));
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun }
895*4882a593Smuzhiyun /* ? host_rw_ofs always ahead of elapsed_dma_ofs by preload size? */
896*4882a593Smuzhiyun ds->pcm_buf_host_rw_ofs += xfercount;
897*4882a593Smuzhiyun ds->pcm_buf_elapsed_dma_ofs += xfercount;
898*4882a593Smuzhiyun snd_pcm_period_elapsed(s);
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun if (!card->hpi->interrupt_mode && dpcm->respawn_timer)
903*4882a593Smuzhiyun add_timer(&dpcm->timer);
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun
snd_card_asihpi_isr(struct hpi_adapter * a)906*4882a593Smuzhiyun static void snd_card_asihpi_isr(struct hpi_adapter *a)
907*4882a593Smuzhiyun {
908*4882a593Smuzhiyun struct snd_card_asihpi *asihpi;
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun WARN_ON(!a || !a->snd_card || !a->snd_card->private_data);
911*4882a593Smuzhiyun asihpi = (struct snd_card_asihpi *)a->snd_card->private_data;
912*4882a593Smuzhiyun if (asihpi->llmode_streampriv)
913*4882a593Smuzhiyun snd_card_asihpi_timer_function(
914*4882a593Smuzhiyun &asihpi->llmode_streampriv->timer);
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun /***************************** PLAYBACK OPS ****************/
snd_card_asihpi_playback_prepare(struct snd_pcm_substream * substream)918*4882a593Smuzhiyun static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
919*4882a593Smuzhiyun substream)
920*4882a593Smuzhiyun {
921*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
922*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun snd_printdd("P%d prepare\n", substream->number);
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
927*4882a593Smuzhiyun dpcm->pcm_buf_host_rw_ofs = 0;
928*4882a593Smuzhiyun dpcm->pcm_buf_dma_ofs = 0;
929*4882a593Smuzhiyun dpcm->pcm_buf_elapsed_dma_ofs = 0;
930*4882a593Smuzhiyun return 0;
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun static snd_pcm_uframes_t
snd_card_asihpi_playback_pointer(struct snd_pcm_substream * substream)934*4882a593Smuzhiyun snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
935*4882a593Smuzhiyun {
936*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
937*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
938*4882a593Smuzhiyun snd_pcm_uframes_t ptr;
939*4882a593Smuzhiyun char name[16];
940*4882a593Smuzhiyun snd_pcm_debug_name(substream, name, sizeof(name));
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
943*4882a593Smuzhiyun snd_printddd("%s, pointer=%ld\n", name, (unsigned long)ptr);
944*4882a593Smuzhiyun return ptr;
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun
snd_card_asihpi_playback_formats(struct snd_card_asihpi * asihpi,u32 h_stream)947*4882a593Smuzhiyun static u64 snd_card_asihpi_playback_formats(struct snd_card_asihpi *asihpi,
948*4882a593Smuzhiyun u32 h_stream)
949*4882a593Smuzhiyun {
950*4882a593Smuzhiyun struct hpi_format hpi_format;
951*4882a593Smuzhiyun u16 format;
952*4882a593Smuzhiyun u16 err;
953*4882a593Smuzhiyun u32 h_control;
954*4882a593Smuzhiyun u32 sample_rate = 48000;
955*4882a593Smuzhiyun u64 formats = 0;
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun /* on cards without SRC, must query at valid rate,
958*4882a593Smuzhiyun * maybe set by external sync
959*4882a593Smuzhiyun */
960*4882a593Smuzhiyun err = hpi_mixer_get_control(asihpi->h_mixer,
961*4882a593Smuzhiyun HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
962*4882a593Smuzhiyun HPI_CONTROL_SAMPLECLOCK, &h_control);
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun if (!err)
965*4882a593Smuzhiyun err = hpi_sample_clock_get_sample_rate(h_control,
966*4882a593Smuzhiyun &sample_rate);
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun for (format = HPI_FORMAT_PCM8_UNSIGNED;
969*4882a593Smuzhiyun format <= HPI_FORMAT_PCM24_SIGNED; format++) {
970*4882a593Smuzhiyun err = hpi_format_create(&hpi_format, asihpi->out_max_chans,
971*4882a593Smuzhiyun format, sample_rate, 128000, 0);
972*4882a593Smuzhiyun if (!err)
973*4882a593Smuzhiyun err = hpi_outstream_query_format(h_stream, &hpi_format);
974*4882a593Smuzhiyun if (!err && (hpi_to_alsa_formats[format] != INVALID_FORMAT))
975*4882a593Smuzhiyun formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]);
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun return formats;
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun
snd_card_asihpi_playback_open(struct snd_pcm_substream * substream)980*4882a593Smuzhiyun static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
981*4882a593Smuzhiyun {
982*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
983*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm;
984*4882a593Smuzhiyun struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
985*4882a593Smuzhiyun struct snd_pcm_hardware snd_card_asihpi_playback;
986*4882a593Smuzhiyun int err;
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
989*4882a593Smuzhiyun if (dpcm == NULL)
990*4882a593Smuzhiyun return -ENOMEM;
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun err = hpi_outstream_open(card->hpi->adapter->index,
993*4882a593Smuzhiyun substream->number, &dpcm->h_stream);
994*4882a593Smuzhiyun hpi_handle_error(err);
995*4882a593Smuzhiyun if (err)
996*4882a593Smuzhiyun kfree(dpcm);
997*4882a593Smuzhiyun if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
998*4882a593Smuzhiyun return -EBUSY;
999*4882a593Smuzhiyun if (err)
1000*4882a593Smuzhiyun return -EIO;
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun /*? also check ASI5000 samplerate source
1003*4882a593Smuzhiyun If external, only support external rate.
1004*4882a593Smuzhiyun If internal and other stream playing, can't switch
1005*4882a593Smuzhiyun */
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun timer_setup(&dpcm->timer, snd_card_asihpi_timer_function, 0);
1008*4882a593Smuzhiyun dpcm->substream = substream;
1009*4882a593Smuzhiyun runtime->private_data = dpcm;
1010*4882a593Smuzhiyun runtime->private_free = snd_card_asihpi_runtime_free;
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun memset(&snd_card_asihpi_playback, 0, sizeof(snd_card_asihpi_playback));
1013*4882a593Smuzhiyun if (!card->hpi->interrupt_mode) {
1014*4882a593Smuzhiyun snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;
1015*4882a593Smuzhiyun snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN;
1016*4882a593Smuzhiyun snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
1017*4882a593Smuzhiyun snd_card_asihpi_playback.periods_min = PERIODS_MIN;
1018*4882a593Smuzhiyun snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
1019*4882a593Smuzhiyun } else {
1020*4882a593Smuzhiyun size_t pbmin = card->update_interval_frames *
1021*4882a593Smuzhiyun card->out_max_chans;
1022*4882a593Smuzhiyun snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;
1023*4882a593Smuzhiyun snd_card_asihpi_playback.period_bytes_min = pbmin;
1024*4882a593Smuzhiyun snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
1025*4882a593Smuzhiyun snd_card_asihpi_playback.periods_min = PERIODS_MIN;
1026*4882a593Smuzhiyun snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / pbmin;
1027*4882a593Smuzhiyun }
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun /* snd_card_asihpi_playback.fifo_size = 0; */
1030*4882a593Smuzhiyun snd_card_asihpi_playback.channels_max = card->out_max_chans;
1031*4882a593Smuzhiyun snd_card_asihpi_playback.channels_min = card->out_min_chans;
1032*4882a593Smuzhiyun snd_card_asihpi_playback.formats =
1033*4882a593Smuzhiyun snd_card_asihpi_playback_formats(card, dpcm->h_stream);
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_playback);
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun snd_card_asihpi_playback.info = SNDRV_PCM_INFO_INTERLEAVED |
1038*4882a593Smuzhiyun SNDRV_PCM_INFO_DOUBLE |
1039*4882a593Smuzhiyun SNDRV_PCM_INFO_BATCH |
1040*4882a593Smuzhiyun SNDRV_PCM_INFO_BLOCK_TRANSFER |
1041*4882a593Smuzhiyun SNDRV_PCM_INFO_PAUSE |
1042*4882a593Smuzhiyun SNDRV_PCM_INFO_MMAP |
1043*4882a593Smuzhiyun SNDRV_PCM_INFO_MMAP_VALID;
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun if (card->support_grouping) {
1046*4882a593Smuzhiyun snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
1047*4882a593Smuzhiyun snd_pcm_set_sync(substream);
1048*4882a593Smuzhiyun }
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun /* struct is copied, so can create initializer dynamically */
1051*4882a593Smuzhiyun runtime->hw = snd_card_asihpi_playback;
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun if (card->can_dma)
1054*4882a593Smuzhiyun err = snd_pcm_hw_constraint_pow2(runtime, 0,
1055*4882a593Smuzhiyun SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1056*4882a593Smuzhiyun if (err < 0)
1057*4882a593Smuzhiyun return err;
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1060*4882a593Smuzhiyun card->update_interval_frames);
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1063*4882a593Smuzhiyun card->update_interval_frames, UINT_MAX);
1064*4882a593Smuzhiyun
1065*4882a593Smuzhiyun snd_printdd("playback open\n");
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun return 0;
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun
snd_card_asihpi_playback_close(struct snd_pcm_substream * substream)1070*4882a593Smuzhiyun static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
1071*4882a593Smuzhiyun {
1072*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
1073*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun hpi_handle_error(hpi_outstream_close(dpcm->h_stream));
1076*4882a593Smuzhiyun snd_printdd("playback close\n");
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun return 0;
1079*4882a593Smuzhiyun }
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun static const struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
1082*4882a593Smuzhiyun .open = snd_card_asihpi_playback_open,
1083*4882a593Smuzhiyun .close = snd_card_asihpi_playback_close,
1084*4882a593Smuzhiyun .hw_params = snd_card_asihpi_pcm_hw_params,
1085*4882a593Smuzhiyun .hw_free = snd_card_asihpi_hw_free,
1086*4882a593Smuzhiyun .prepare = snd_card_asihpi_playback_prepare,
1087*4882a593Smuzhiyun .trigger = snd_card_asihpi_trigger,
1088*4882a593Smuzhiyun .pointer = snd_card_asihpi_playback_pointer,
1089*4882a593Smuzhiyun };
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun /***************************** CAPTURE OPS ****************/
1092*4882a593Smuzhiyun static snd_pcm_uframes_t
snd_card_asihpi_capture_pointer(struct snd_pcm_substream * substream)1093*4882a593Smuzhiyun snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
1094*4882a593Smuzhiyun {
1095*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
1096*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1097*4882a593Smuzhiyun char name[16];
1098*4882a593Smuzhiyun snd_pcm_debug_name(substream, name, sizeof(name));
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun snd_printddd("%s, pointer=%d\n", name, dpcm->pcm_buf_dma_ofs);
1101*4882a593Smuzhiyun /* NOTE Unlike playback can't use actual samples_played
1102*4882a593Smuzhiyun for the capture position, because those samples aren't yet in
1103*4882a593Smuzhiyun the local buffer available for reading.
1104*4882a593Smuzhiyun */
1105*4882a593Smuzhiyun return bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
1106*4882a593Smuzhiyun }
1107*4882a593Smuzhiyun
snd_card_asihpi_capture_prepare(struct snd_pcm_substream * substream)1108*4882a593Smuzhiyun static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
1109*4882a593Smuzhiyun {
1110*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
1111*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun hpi_handle_error(hpi_instream_reset(dpcm->h_stream));
1114*4882a593Smuzhiyun dpcm->pcm_buf_host_rw_ofs = 0;
1115*4882a593Smuzhiyun dpcm->pcm_buf_dma_ofs = 0;
1116*4882a593Smuzhiyun dpcm->pcm_buf_elapsed_dma_ofs = 0;
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun snd_printdd("Capture Prepare %d\n", substream->number);
1119*4882a593Smuzhiyun return 0;
1120*4882a593Smuzhiyun }
1121*4882a593Smuzhiyun
snd_card_asihpi_capture_formats(struct snd_card_asihpi * asihpi,u32 h_stream)1122*4882a593Smuzhiyun static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi,
1123*4882a593Smuzhiyun u32 h_stream)
1124*4882a593Smuzhiyun {
1125*4882a593Smuzhiyun struct hpi_format hpi_format;
1126*4882a593Smuzhiyun u16 format;
1127*4882a593Smuzhiyun u16 err;
1128*4882a593Smuzhiyun u32 h_control;
1129*4882a593Smuzhiyun u32 sample_rate = 48000;
1130*4882a593Smuzhiyun u64 formats = 0;
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun /* on cards without SRC, must query at valid rate,
1133*4882a593Smuzhiyun maybe set by external sync */
1134*4882a593Smuzhiyun err = hpi_mixer_get_control(asihpi->h_mixer,
1135*4882a593Smuzhiyun HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
1136*4882a593Smuzhiyun HPI_CONTROL_SAMPLECLOCK, &h_control);
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun if (!err)
1139*4882a593Smuzhiyun err = hpi_sample_clock_get_sample_rate(h_control,
1140*4882a593Smuzhiyun &sample_rate);
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun for (format = HPI_FORMAT_PCM8_UNSIGNED;
1143*4882a593Smuzhiyun format <= HPI_FORMAT_PCM24_SIGNED; format++) {
1144*4882a593Smuzhiyun
1145*4882a593Smuzhiyun err = hpi_format_create(&hpi_format, asihpi->in_max_chans,
1146*4882a593Smuzhiyun format, sample_rate, 128000, 0);
1147*4882a593Smuzhiyun if (!err)
1148*4882a593Smuzhiyun err = hpi_instream_query_format(h_stream, &hpi_format);
1149*4882a593Smuzhiyun if (!err && (hpi_to_alsa_formats[format] != INVALID_FORMAT))
1150*4882a593Smuzhiyun formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]);
1151*4882a593Smuzhiyun }
1152*4882a593Smuzhiyun return formats;
1153*4882a593Smuzhiyun }
1154*4882a593Smuzhiyun
snd_card_asihpi_capture_open(struct snd_pcm_substream * substream)1155*4882a593Smuzhiyun static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
1156*4882a593Smuzhiyun {
1157*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
1158*4882a593Smuzhiyun struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
1159*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm;
1160*4882a593Smuzhiyun struct snd_pcm_hardware snd_card_asihpi_capture;
1161*4882a593Smuzhiyun int err;
1162*4882a593Smuzhiyun
1163*4882a593Smuzhiyun dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
1164*4882a593Smuzhiyun if (dpcm == NULL)
1165*4882a593Smuzhiyun return -ENOMEM;
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun snd_printdd("capture open adapter %d stream %d\n",
1168*4882a593Smuzhiyun card->hpi->adapter->index, substream->number);
1169*4882a593Smuzhiyun
1170*4882a593Smuzhiyun err = hpi_handle_error(
1171*4882a593Smuzhiyun hpi_instream_open(card->hpi->adapter->index,
1172*4882a593Smuzhiyun substream->number, &dpcm->h_stream));
1173*4882a593Smuzhiyun if (err)
1174*4882a593Smuzhiyun kfree(dpcm);
1175*4882a593Smuzhiyun if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
1176*4882a593Smuzhiyun return -EBUSY;
1177*4882a593Smuzhiyun if (err)
1178*4882a593Smuzhiyun return -EIO;
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun timer_setup(&dpcm->timer, snd_card_asihpi_timer_function, 0);
1181*4882a593Smuzhiyun dpcm->substream = substream;
1182*4882a593Smuzhiyun runtime->private_data = dpcm;
1183*4882a593Smuzhiyun runtime->private_free = snd_card_asihpi_runtime_free;
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun memset(&snd_card_asihpi_capture, 0, sizeof(snd_card_asihpi_capture));
1186*4882a593Smuzhiyun if (!card->hpi->interrupt_mode) {
1187*4882a593Smuzhiyun snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;
1188*4882a593Smuzhiyun snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN;
1189*4882a593Smuzhiyun snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
1190*4882a593Smuzhiyun snd_card_asihpi_capture.periods_min = PERIODS_MIN;
1191*4882a593Smuzhiyun snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
1192*4882a593Smuzhiyun } else {
1193*4882a593Smuzhiyun size_t pbmin = card->update_interval_frames *
1194*4882a593Smuzhiyun card->out_max_chans;
1195*4882a593Smuzhiyun snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;
1196*4882a593Smuzhiyun snd_card_asihpi_capture.period_bytes_min = pbmin;
1197*4882a593Smuzhiyun snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
1198*4882a593Smuzhiyun snd_card_asihpi_capture.periods_min = PERIODS_MIN;
1199*4882a593Smuzhiyun snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / pbmin;
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun /* snd_card_asihpi_capture.fifo_size = 0; */
1202*4882a593Smuzhiyun snd_card_asihpi_capture.channels_max = card->in_max_chans;
1203*4882a593Smuzhiyun snd_card_asihpi_capture.channels_min = card->in_min_chans;
1204*4882a593Smuzhiyun snd_card_asihpi_capture.formats =
1205*4882a593Smuzhiyun snd_card_asihpi_capture_formats(card, dpcm->h_stream);
1206*4882a593Smuzhiyun snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture);
1207*4882a593Smuzhiyun snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED |
1208*4882a593Smuzhiyun SNDRV_PCM_INFO_MMAP |
1209*4882a593Smuzhiyun SNDRV_PCM_INFO_MMAP_VALID;
1210*4882a593Smuzhiyun
1211*4882a593Smuzhiyun if (card->support_grouping)
1212*4882a593Smuzhiyun snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
1213*4882a593Smuzhiyun
1214*4882a593Smuzhiyun runtime->hw = snd_card_asihpi_capture;
1215*4882a593Smuzhiyun
1216*4882a593Smuzhiyun if (card->can_dma)
1217*4882a593Smuzhiyun err = snd_pcm_hw_constraint_pow2(runtime, 0,
1218*4882a593Smuzhiyun SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1219*4882a593Smuzhiyun if (err < 0)
1220*4882a593Smuzhiyun return err;
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1223*4882a593Smuzhiyun card->update_interval_frames);
1224*4882a593Smuzhiyun snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1225*4882a593Smuzhiyun card->update_interval_frames, UINT_MAX);
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun snd_pcm_set_sync(substream);
1228*4882a593Smuzhiyun
1229*4882a593Smuzhiyun return 0;
1230*4882a593Smuzhiyun }
1231*4882a593Smuzhiyun
snd_card_asihpi_capture_close(struct snd_pcm_substream * substream)1232*4882a593Smuzhiyun static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
1233*4882a593Smuzhiyun {
1234*4882a593Smuzhiyun struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun hpi_handle_error(hpi_instream_close(dpcm->h_stream));
1237*4882a593Smuzhiyun return 0;
1238*4882a593Smuzhiyun }
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun static const struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
1241*4882a593Smuzhiyun .open = snd_card_asihpi_capture_open,
1242*4882a593Smuzhiyun .close = snd_card_asihpi_capture_close,
1243*4882a593Smuzhiyun .hw_params = snd_card_asihpi_pcm_hw_params,
1244*4882a593Smuzhiyun .hw_free = snd_card_asihpi_hw_free,
1245*4882a593Smuzhiyun .prepare = snd_card_asihpi_capture_prepare,
1246*4882a593Smuzhiyun .trigger = snd_card_asihpi_trigger,
1247*4882a593Smuzhiyun .pointer = snd_card_asihpi_capture_pointer,
1248*4882a593Smuzhiyun };
1249*4882a593Smuzhiyun
snd_card_asihpi_pcm_new(struct snd_card_asihpi * asihpi,int device)1250*4882a593Smuzhiyun static int snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device)
1251*4882a593Smuzhiyun {
1252*4882a593Smuzhiyun struct snd_pcm *pcm;
1253*4882a593Smuzhiyun int err;
1254*4882a593Smuzhiyun u16 num_instreams, num_outstreams, x16;
1255*4882a593Smuzhiyun u32 x32;
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun err = hpi_adapter_get_info(asihpi->hpi->adapter->index,
1258*4882a593Smuzhiyun &num_outstreams, &num_instreams,
1259*4882a593Smuzhiyun &x16, &x32, &x16);
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun err = snd_pcm_new(asihpi->card, "Asihpi PCM", device,
1262*4882a593Smuzhiyun num_outstreams, num_instreams, &pcm);
1263*4882a593Smuzhiyun if (err < 0)
1264*4882a593Smuzhiyun return err;
1265*4882a593Smuzhiyun
1266*4882a593Smuzhiyun /* pointer to ops struct is stored, dont change ops afterwards! */
1267*4882a593Smuzhiyun snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1268*4882a593Smuzhiyun &snd_card_asihpi_playback_mmap_ops);
1269*4882a593Smuzhiyun snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1270*4882a593Smuzhiyun &snd_card_asihpi_capture_mmap_ops);
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun pcm->private_data = asihpi;
1273*4882a593Smuzhiyun pcm->info_flags = 0;
1274*4882a593Smuzhiyun strcpy(pcm->name, "Asihpi PCM");
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun /*? do we want to emulate MMAP for non-BBM cards?
1277*4882a593Smuzhiyun Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */
1278*4882a593Smuzhiyun snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
1279*4882a593Smuzhiyun &asihpi->pci->dev,
1280*4882a593Smuzhiyun 64*1024, BUFFER_BYTES_MAX);
1281*4882a593Smuzhiyun
1282*4882a593Smuzhiyun return 0;
1283*4882a593Smuzhiyun }
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun /***************************** MIXER CONTROLS ****************/
1286*4882a593Smuzhiyun struct hpi_control {
1287*4882a593Smuzhiyun u32 h_control;
1288*4882a593Smuzhiyun u16 control_type;
1289*4882a593Smuzhiyun u16 src_node_type;
1290*4882a593Smuzhiyun u16 src_node_index;
1291*4882a593Smuzhiyun u16 dst_node_type;
1292*4882a593Smuzhiyun u16 dst_node_index;
1293*4882a593Smuzhiyun u16 band;
1294*4882a593Smuzhiyun char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* copied to snd_ctl_elem_id.name[44]; */
1295*4882a593Smuzhiyun };
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun static const char * const asihpi_tuner_band_names[] = {
1298*4882a593Smuzhiyun "invalid",
1299*4882a593Smuzhiyun "AM",
1300*4882a593Smuzhiyun "FM mono",
1301*4882a593Smuzhiyun "TV NTSC-M",
1302*4882a593Smuzhiyun "FM stereo",
1303*4882a593Smuzhiyun "AUX",
1304*4882a593Smuzhiyun "TV PAL BG",
1305*4882a593Smuzhiyun "TV PAL I",
1306*4882a593Smuzhiyun "TV PAL DK",
1307*4882a593Smuzhiyun "TV SECAM",
1308*4882a593Smuzhiyun "TV DAB",
1309*4882a593Smuzhiyun };
1310*4882a593Smuzhiyun /* Number of strings must match the enumerations for HPI_TUNER_BAND in hpi.h */
1311*4882a593Smuzhiyun compile_time_assert(
1312*4882a593Smuzhiyun (ARRAY_SIZE(asihpi_tuner_band_names) ==
1313*4882a593Smuzhiyun (HPI_TUNER_BAND_LAST+1)),
1314*4882a593Smuzhiyun assert_tuner_band_names_size);
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun static const char * const asihpi_src_names[] = {
1317*4882a593Smuzhiyun "no source",
1318*4882a593Smuzhiyun "PCM",
1319*4882a593Smuzhiyun "Line",
1320*4882a593Smuzhiyun "Digital",
1321*4882a593Smuzhiyun "Tuner",
1322*4882a593Smuzhiyun "RF",
1323*4882a593Smuzhiyun "Clock",
1324*4882a593Smuzhiyun "Bitstream",
1325*4882a593Smuzhiyun "Mic",
1326*4882a593Smuzhiyun "Net",
1327*4882a593Smuzhiyun "Analog",
1328*4882a593Smuzhiyun "Adapter",
1329*4882a593Smuzhiyun "RTP",
1330*4882a593Smuzhiyun "Internal",
1331*4882a593Smuzhiyun "AVB",
1332*4882a593Smuzhiyun "BLU-Link"
1333*4882a593Smuzhiyun };
1334*4882a593Smuzhiyun /* Number of strings must match the enumerations for HPI_SOURCENODES in hpi.h */
1335*4882a593Smuzhiyun compile_time_assert(
1336*4882a593Smuzhiyun (ARRAY_SIZE(asihpi_src_names) ==
1337*4882a593Smuzhiyun (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
1338*4882a593Smuzhiyun assert_src_names_size);
1339*4882a593Smuzhiyun
1340*4882a593Smuzhiyun static const char * const asihpi_dst_names[] = {
1341*4882a593Smuzhiyun "no destination",
1342*4882a593Smuzhiyun "PCM",
1343*4882a593Smuzhiyun "Line",
1344*4882a593Smuzhiyun "Digital",
1345*4882a593Smuzhiyun "RF",
1346*4882a593Smuzhiyun "Speaker",
1347*4882a593Smuzhiyun "Net",
1348*4882a593Smuzhiyun "Analog",
1349*4882a593Smuzhiyun "RTP",
1350*4882a593Smuzhiyun "AVB",
1351*4882a593Smuzhiyun "Internal",
1352*4882a593Smuzhiyun "BLU-Link"
1353*4882a593Smuzhiyun };
1354*4882a593Smuzhiyun /* Number of strings must match the enumerations for HPI_DESTNODES in hpi.h */
1355*4882a593Smuzhiyun compile_time_assert(
1356*4882a593Smuzhiyun (ARRAY_SIZE(asihpi_dst_names) ==
1357*4882a593Smuzhiyun (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),
1358*4882a593Smuzhiyun assert_dst_names_size);
1359*4882a593Smuzhiyun
ctl_add(struct snd_card * card,struct snd_kcontrol_new * ctl,struct snd_card_asihpi * asihpi)1360*4882a593Smuzhiyun static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
1361*4882a593Smuzhiyun struct snd_card_asihpi *asihpi)
1362*4882a593Smuzhiyun {
1363*4882a593Smuzhiyun int err;
1364*4882a593Smuzhiyun
1365*4882a593Smuzhiyun err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi));
1366*4882a593Smuzhiyun if (err < 0)
1367*4882a593Smuzhiyun return err;
1368*4882a593Smuzhiyun else if (mixer_dump)
1369*4882a593Smuzhiyun dev_info(&asihpi->pci->dev, "added %s(%d)\n", ctl->name, ctl->index);
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun return 0;
1372*4882a593Smuzhiyun }
1373*4882a593Smuzhiyun
1374*4882a593Smuzhiyun /* Convert HPI control name and location into ALSA control name */
asihpi_ctl_init(struct snd_kcontrol_new * snd_control,struct hpi_control * hpi_ctl,char * name)1375*4882a593Smuzhiyun static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
1376*4882a593Smuzhiyun struct hpi_control *hpi_ctl,
1377*4882a593Smuzhiyun char *name)
1378*4882a593Smuzhiyun {
1379*4882a593Smuzhiyun char *dir;
1380*4882a593Smuzhiyun memset(snd_control, 0, sizeof(*snd_control));
1381*4882a593Smuzhiyun snd_control->name = hpi_ctl->name;
1382*4882a593Smuzhiyun snd_control->private_value = hpi_ctl->h_control;
1383*4882a593Smuzhiyun snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1384*4882a593Smuzhiyun snd_control->index = 0;
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun if (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE == HPI_SOURCENODE_CLOCK_SOURCE)
1387*4882a593Smuzhiyun dir = ""; /* clock is neither capture nor playback */
1388*4882a593Smuzhiyun else if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
1389*4882a593Smuzhiyun dir = "Capture "; /* On or towards a PCM capture destination*/
1390*4882a593Smuzhiyun else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
1391*4882a593Smuzhiyun (!hpi_ctl->dst_node_type))
1392*4882a593Smuzhiyun dir = "Capture "; /* On a source node that is not PCM playback */
1393*4882a593Smuzhiyun else if (hpi_ctl->src_node_type &&
1394*4882a593Smuzhiyun (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
1395*4882a593Smuzhiyun (hpi_ctl->dst_node_type))
1396*4882a593Smuzhiyun dir = "Monitor Playback "; /* Between an input and an output */
1397*4882a593Smuzhiyun else
1398*4882a593Smuzhiyun dir = "Playback "; /* PCM Playback source, or output node */
1399*4882a593Smuzhiyun
1400*4882a593Smuzhiyun if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
1401*4882a593Smuzhiyun sprintf(hpi_ctl->name, "%s %d %s %d %s%s",
1402*4882a593Smuzhiyun asihpi_src_names[hpi_ctl->src_node_type],
1403*4882a593Smuzhiyun hpi_ctl->src_node_index,
1404*4882a593Smuzhiyun asihpi_dst_names[hpi_ctl->dst_node_type],
1405*4882a593Smuzhiyun hpi_ctl->dst_node_index,
1406*4882a593Smuzhiyun dir, name);
1407*4882a593Smuzhiyun else if (hpi_ctl->dst_node_type) {
1408*4882a593Smuzhiyun sprintf(hpi_ctl->name, "%s %d %s%s",
1409*4882a593Smuzhiyun asihpi_dst_names[hpi_ctl->dst_node_type],
1410*4882a593Smuzhiyun hpi_ctl->dst_node_index,
1411*4882a593Smuzhiyun dir, name);
1412*4882a593Smuzhiyun } else {
1413*4882a593Smuzhiyun sprintf(hpi_ctl->name, "%s %d %s%s",
1414*4882a593Smuzhiyun asihpi_src_names[hpi_ctl->src_node_type],
1415*4882a593Smuzhiyun hpi_ctl->src_node_index,
1416*4882a593Smuzhiyun dir, name);
1417*4882a593Smuzhiyun }
1418*4882a593Smuzhiyun /* printk(KERN_INFO "Adding %s %d to %d ", hpi_ctl->name,
1419*4882a593Smuzhiyun hpi_ctl->wSrcNodeType, hpi_ctl->wDstNodeType); */
1420*4882a593Smuzhiyun }
1421*4882a593Smuzhiyun
1422*4882a593Smuzhiyun /*------------------------------------------------------------
1423*4882a593Smuzhiyun Volume controls
1424*4882a593Smuzhiyun ------------------------------------------------------------*/
1425*4882a593Smuzhiyun #define VOL_STEP_mB 1
snd_asihpi_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1426*4882a593Smuzhiyun static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,
1427*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
1428*4882a593Smuzhiyun {
1429*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1430*4882a593Smuzhiyun u32 count;
1431*4882a593Smuzhiyun u16 err;
1432*4882a593Smuzhiyun /* native gains are in millibels */
1433*4882a593Smuzhiyun short min_gain_mB;
1434*4882a593Smuzhiyun short max_gain_mB;
1435*4882a593Smuzhiyun short step_gain_mB;
1436*4882a593Smuzhiyun
1437*4882a593Smuzhiyun err = hpi_volume_query_range(h_control,
1438*4882a593Smuzhiyun &min_gain_mB, &max_gain_mB, &step_gain_mB);
1439*4882a593Smuzhiyun if (err) {
1440*4882a593Smuzhiyun max_gain_mB = 0;
1441*4882a593Smuzhiyun min_gain_mB = -10000;
1442*4882a593Smuzhiyun step_gain_mB = VOL_STEP_mB;
1443*4882a593Smuzhiyun }
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun err = hpi_meter_query_channels(h_control, &count);
1446*4882a593Smuzhiyun if (err)
1447*4882a593Smuzhiyun count = HPI_MAX_CHANNELS;
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1450*4882a593Smuzhiyun uinfo->count = count;
1451*4882a593Smuzhiyun uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB;
1452*4882a593Smuzhiyun uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB;
1453*4882a593Smuzhiyun uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB;
1454*4882a593Smuzhiyun return 0;
1455*4882a593Smuzhiyun }
1456*4882a593Smuzhiyun
snd_asihpi_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1457*4882a593Smuzhiyun static int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,
1458*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1459*4882a593Smuzhiyun {
1460*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1461*4882a593Smuzhiyun short an_gain_mB[HPI_MAX_CHANNELS];
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun hpi_handle_error(hpi_volume_get_gain(h_control, an_gain_mB));
1464*4882a593Smuzhiyun ucontrol->value.integer.value[0] = an_gain_mB[0] / VOL_STEP_mB;
1465*4882a593Smuzhiyun ucontrol->value.integer.value[1] = an_gain_mB[1] / VOL_STEP_mB;
1466*4882a593Smuzhiyun
1467*4882a593Smuzhiyun return 0;
1468*4882a593Smuzhiyun }
1469*4882a593Smuzhiyun
snd_asihpi_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1470*4882a593Smuzhiyun static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
1471*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1472*4882a593Smuzhiyun {
1473*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1474*4882a593Smuzhiyun short an_gain_mB[HPI_MAX_CHANNELS];
1475*4882a593Smuzhiyun
1476*4882a593Smuzhiyun an_gain_mB[0] =
1477*4882a593Smuzhiyun (ucontrol->value.integer.value[0]) * VOL_STEP_mB;
1478*4882a593Smuzhiyun an_gain_mB[1] =
1479*4882a593Smuzhiyun (ucontrol->value.integer.value[1]) * VOL_STEP_mB;
1480*4882a593Smuzhiyun /* change = asihpi->mixer_volume[addr][0] != left ||
1481*4882a593Smuzhiyun asihpi->mixer_volume[addr][1] != right;
1482*4882a593Smuzhiyun */
1483*4882a593Smuzhiyun hpi_handle_error(hpi_volume_set_gain(h_control, an_gain_mB));
1484*4882a593Smuzhiyun return 1;
1485*4882a593Smuzhiyun }
1486*4882a593Smuzhiyun
1487*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
1488*4882a593Smuzhiyun
1489*4882a593Smuzhiyun #define snd_asihpi_volume_mute_info snd_ctl_boolean_mono_info
1490*4882a593Smuzhiyun
snd_asihpi_volume_mute_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1491*4882a593Smuzhiyun static int snd_asihpi_volume_mute_get(struct snd_kcontrol *kcontrol,
1492*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1493*4882a593Smuzhiyun {
1494*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1495*4882a593Smuzhiyun u32 mute;
1496*4882a593Smuzhiyun
1497*4882a593Smuzhiyun hpi_handle_error(hpi_volume_get_mute(h_control, &mute));
1498*4882a593Smuzhiyun ucontrol->value.integer.value[0] = mute ? 0 : 1;
1499*4882a593Smuzhiyun
1500*4882a593Smuzhiyun return 0;
1501*4882a593Smuzhiyun }
1502*4882a593Smuzhiyun
snd_asihpi_volume_mute_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1503*4882a593Smuzhiyun static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol,
1504*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1505*4882a593Smuzhiyun {
1506*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1507*4882a593Smuzhiyun /* HPI currently only supports all or none muting of multichannel volume
1508*4882a593Smuzhiyun ALSA Switch element has opposite sense to HPI mute: on==unmuted, off=muted
1509*4882a593Smuzhiyun */
1510*4882a593Smuzhiyun int mute = ucontrol->value.integer.value[0] ? 0 : HPI_BITMASK_ALL_CHANNELS;
1511*4882a593Smuzhiyun hpi_handle_error(hpi_volume_set_mute(h_control, mute));
1512*4882a593Smuzhiyun return 1;
1513*4882a593Smuzhiyun }
1514*4882a593Smuzhiyun
snd_asihpi_volume_add(struct snd_card_asihpi * asihpi,struct hpi_control * hpi_ctl)1515*4882a593Smuzhiyun static int snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
1516*4882a593Smuzhiyun struct hpi_control *hpi_ctl)
1517*4882a593Smuzhiyun {
1518*4882a593Smuzhiyun struct snd_card *card = asihpi->card;
1519*4882a593Smuzhiyun struct snd_kcontrol_new snd_control;
1520*4882a593Smuzhiyun int err;
1521*4882a593Smuzhiyun u32 mute;
1522*4882a593Smuzhiyun
1523*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Volume");
1524*4882a593Smuzhiyun snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1525*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1526*4882a593Smuzhiyun snd_control.info = snd_asihpi_volume_info;
1527*4882a593Smuzhiyun snd_control.get = snd_asihpi_volume_get;
1528*4882a593Smuzhiyun snd_control.put = snd_asihpi_volume_put;
1529*4882a593Smuzhiyun snd_control.tlv.p = db_scale_100;
1530*4882a593Smuzhiyun
1531*4882a593Smuzhiyun err = ctl_add(card, &snd_control, asihpi);
1532*4882a593Smuzhiyun if (err)
1533*4882a593Smuzhiyun return err;
1534*4882a593Smuzhiyun
1535*4882a593Smuzhiyun if (hpi_volume_get_mute(hpi_ctl->h_control, &mute) == 0) {
1536*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Switch");
1537*4882a593Smuzhiyun snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1538*4882a593Smuzhiyun snd_control.info = snd_asihpi_volume_mute_info;
1539*4882a593Smuzhiyun snd_control.get = snd_asihpi_volume_mute_get;
1540*4882a593Smuzhiyun snd_control.put = snd_asihpi_volume_mute_put;
1541*4882a593Smuzhiyun err = ctl_add(card, &snd_control, asihpi);
1542*4882a593Smuzhiyun }
1543*4882a593Smuzhiyun return err;
1544*4882a593Smuzhiyun }
1545*4882a593Smuzhiyun
1546*4882a593Smuzhiyun /*------------------------------------------------------------
1547*4882a593Smuzhiyun Level controls
1548*4882a593Smuzhiyun ------------------------------------------------------------*/
snd_asihpi_level_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1549*4882a593Smuzhiyun static int snd_asihpi_level_info(struct snd_kcontrol *kcontrol,
1550*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
1551*4882a593Smuzhiyun {
1552*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1553*4882a593Smuzhiyun u16 err;
1554*4882a593Smuzhiyun short min_gain_mB;
1555*4882a593Smuzhiyun short max_gain_mB;
1556*4882a593Smuzhiyun short step_gain_mB;
1557*4882a593Smuzhiyun
1558*4882a593Smuzhiyun err =
1559*4882a593Smuzhiyun hpi_level_query_range(h_control, &min_gain_mB,
1560*4882a593Smuzhiyun &max_gain_mB, &step_gain_mB);
1561*4882a593Smuzhiyun if (err) {
1562*4882a593Smuzhiyun max_gain_mB = 2400;
1563*4882a593Smuzhiyun min_gain_mB = -1000;
1564*4882a593Smuzhiyun step_gain_mB = 100;
1565*4882a593Smuzhiyun }
1566*4882a593Smuzhiyun
1567*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1568*4882a593Smuzhiyun uinfo->count = 2;
1569*4882a593Smuzhiyun uinfo->value.integer.min = min_gain_mB / HPI_UNITS_PER_dB;
1570*4882a593Smuzhiyun uinfo->value.integer.max = max_gain_mB / HPI_UNITS_PER_dB;
1571*4882a593Smuzhiyun uinfo->value.integer.step = step_gain_mB / HPI_UNITS_PER_dB;
1572*4882a593Smuzhiyun return 0;
1573*4882a593Smuzhiyun }
1574*4882a593Smuzhiyun
snd_asihpi_level_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1575*4882a593Smuzhiyun static int snd_asihpi_level_get(struct snd_kcontrol *kcontrol,
1576*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1577*4882a593Smuzhiyun {
1578*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1579*4882a593Smuzhiyun short an_gain_mB[HPI_MAX_CHANNELS];
1580*4882a593Smuzhiyun
1581*4882a593Smuzhiyun hpi_handle_error(hpi_level_get_gain(h_control, an_gain_mB));
1582*4882a593Smuzhiyun ucontrol->value.integer.value[0] =
1583*4882a593Smuzhiyun an_gain_mB[0] / HPI_UNITS_PER_dB;
1584*4882a593Smuzhiyun ucontrol->value.integer.value[1] =
1585*4882a593Smuzhiyun an_gain_mB[1] / HPI_UNITS_PER_dB;
1586*4882a593Smuzhiyun
1587*4882a593Smuzhiyun return 0;
1588*4882a593Smuzhiyun }
1589*4882a593Smuzhiyun
snd_asihpi_level_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1590*4882a593Smuzhiyun static int snd_asihpi_level_put(struct snd_kcontrol *kcontrol,
1591*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1592*4882a593Smuzhiyun {
1593*4882a593Smuzhiyun int change;
1594*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1595*4882a593Smuzhiyun short an_gain_mB[HPI_MAX_CHANNELS];
1596*4882a593Smuzhiyun
1597*4882a593Smuzhiyun an_gain_mB[0] =
1598*4882a593Smuzhiyun (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
1599*4882a593Smuzhiyun an_gain_mB[1] =
1600*4882a593Smuzhiyun (ucontrol->value.integer.value[1]) * HPI_UNITS_PER_dB;
1601*4882a593Smuzhiyun /* change = asihpi->mixer_level[addr][0] != left ||
1602*4882a593Smuzhiyun asihpi->mixer_level[addr][1] != right;
1603*4882a593Smuzhiyun */
1604*4882a593Smuzhiyun change = 1;
1605*4882a593Smuzhiyun hpi_handle_error(hpi_level_set_gain(h_control, an_gain_mB));
1606*4882a593Smuzhiyun return change;
1607*4882a593Smuzhiyun }
1608*4882a593Smuzhiyun
1609*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0);
1610*4882a593Smuzhiyun
snd_asihpi_level_add(struct snd_card_asihpi * asihpi,struct hpi_control * hpi_ctl)1611*4882a593Smuzhiyun static int snd_asihpi_level_add(struct snd_card_asihpi *asihpi,
1612*4882a593Smuzhiyun struct hpi_control *hpi_ctl)
1613*4882a593Smuzhiyun {
1614*4882a593Smuzhiyun struct snd_card *card = asihpi->card;
1615*4882a593Smuzhiyun struct snd_kcontrol_new snd_control;
1616*4882a593Smuzhiyun
1617*4882a593Smuzhiyun /* can't use 'volume' cos some nodes have volume as well */
1618*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Level");
1619*4882a593Smuzhiyun snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1620*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1621*4882a593Smuzhiyun snd_control.info = snd_asihpi_level_info;
1622*4882a593Smuzhiyun snd_control.get = snd_asihpi_level_get;
1623*4882a593Smuzhiyun snd_control.put = snd_asihpi_level_put;
1624*4882a593Smuzhiyun snd_control.tlv.p = db_scale_level;
1625*4882a593Smuzhiyun
1626*4882a593Smuzhiyun return ctl_add(card, &snd_control, asihpi);
1627*4882a593Smuzhiyun }
1628*4882a593Smuzhiyun
1629*4882a593Smuzhiyun /*------------------------------------------------------------
1630*4882a593Smuzhiyun AESEBU controls
1631*4882a593Smuzhiyun ------------------------------------------------------------*/
1632*4882a593Smuzhiyun
1633*4882a593Smuzhiyun /* AESEBU format */
1634*4882a593Smuzhiyun static const char * const asihpi_aesebu_format_names[] = {
1635*4882a593Smuzhiyun "N/A", "S/PDIF", "AES/EBU" };
1636*4882a593Smuzhiyun
snd_asihpi_aesebu_format_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1637*4882a593Smuzhiyun static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
1638*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
1639*4882a593Smuzhiyun {
1640*4882a593Smuzhiyun return snd_ctl_enum_info(uinfo, 1, 3, asihpi_aesebu_format_names);
1641*4882a593Smuzhiyun }
1642*4882a593Smuzhiyun
snd_asihpi_aesebu_format_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol,u16 (* func)(u32,u16 *))1643*4882a593Smuzhiyun static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
1644*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol,
1645*4882a593Smuzhiyun u16 (*func)(u32, u16 *))
1646*4882a593Smuzhiyun {
1647*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1648*4882a593Smuzhiyun u16 source, err;
1649*4882a593Smuzhiyun
1650*4882a593Smuzhiyun err = func(h_control, &source);
1651*4882a593Smuzhiyun
1652*4882a593Smuzhiyun /* default to N/A */
1653*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = 0;
1654*4882a593Smuzhiyun /* return success but set the control to N/A */
1655*4882a593Smuzhiyun if (err)
1656*4882a593Smuzhiyun return 0;
1657*4882a593Smuzhiyun if (source == HPI_AESEBU_FORMAT_SPDIF)
1658*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = 1;
1659*4882a593Smuzhiyun if (source == HPI_AESEBU_FORMAT_AESEBU)
1660*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = 2;
1661*4882a593Smuzhiyun
1662*4882a593Smuzhiyun return 0;
1663*4882a593Smuzhiyun }
1664*4882a593Smuzhiyun
snd_asihpi_aesebu_format_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol,u16 (* func)(u32,u16))1665*4882a593Smuzhiyun static int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,
1666*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol,
1667*4882a593Smuzhiyun u16 (*func)(u32, u16))
1668*4882a593Smuzhiyun {
1669*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1670*4882a593Smuzhiyun
1671*4882a593Smuzhiyun /* default to S/PDIF */
1672*4882a593Smuzhiyun u16 source = HPI_AESEBU_FORMAT_SPDIF;
1673*4882a593Smuzhiyun
1674*4882a593Smuzhiyun if (ucontrol->value.enumerated.item[0] == 1)
1675*4882a593Smuzhiyun source = HPI_AESEBU_FORMAT_SPDIF;
1676*4882a593Smuzhiyun if (ucontrol->value.enumerated.item[0] == 2)
1677*4882a593Smuzhiyun source = HPI_AESEBU_FORMAT_AESEBU;
1678*4882a593Smuzhiyun
1679*4882a593Smuzhiyun if (func(h_control, source) != 0)
1680*4882a593Smuzhiyun return -EINVAL;
1681*4882a593Smuzhiyun
1682*4882a593Smuzhiyun return 1;
1683*4882a593Smuzhiyun }
1684*4882a593Smuzhiyun
snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1685*4882a593Smuzhiyun static int snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol *kcontrol,
1686*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol) {
1687*4882a593Smuzhiyun return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
1688*4882a593Smuzhiyun hpi_aesebu_receiver_get_format);
1689*4882a593Smuzhiyun }
1690*4882a593Smuzhiyun
snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1691*4882a593Smuzhiyun static int snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol *kcontrol,
1692*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol) {
1693*4882a593Smuzhiyun return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
1694*4882a593Smuzhiyun hpi_aesebu_receiver_set_format);
1695*4882a593Smuzhiyun }
1696*4882a593Smuzhiyun
snd_asihpi_aesebu_rxstatus_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1697*4882a593Smuzhiyun static int snd_asihpi_aesebu_rxstatus_info(struct snd_kcontrol *kcontrol,
1698*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
1699*4882a593Smuzhiyun {
1700*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1701*4882a593Smuzhiyun uinfo->count = 1;
1702*4882a593Smuzhiyun
1703*4882a593Smuzhiyun uinfo->value.integer.min = 0;
1704*4882a593Smuzhiyun uinfo->value.integer.max = 0X1F;
1705*4882a593Smuzhiyun uinfo->value.integer.step = 1;
1706*4882a593Smuzhiyun
1707*4882a593Smuzhiyun return 0;
1708*4882a593Smuzhiyun }
1709*4882a593Smuzhiyun
snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1710*4882a593Smuzhiyun static int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol,
1711*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol) {
1712*4882a593Smuzhiyun
1713*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1714*4882a593Smuzhiyun u16 status;
1715*4882a593Smuzhiyun
1716*4882a593Smuzhiyun hpi_handle_error(hpi_aesebu_receiver_get_error_status(
1717*4882a593Smuzhiyun h_control, &status));
1718*4882a593Smuzhiyun ucontrol->value.integer.value[0] = status;
1719*4882a593Smuzhiyun return 0;
1720*4882a593Smuzhiyun }
1721*4882a593Smuzhiyun
snd_asihpi_aesebu_rx_add(struct snd_card_asihpi * asihpi,struct hpi_control * hpi_ctl)1722*4882a593Smuzhiyun static int snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,
1723*4882a593Smuzhiyun struct hpi_control *hpi_ctl)
1724*4882a593Smuzhiyun {
1725*4882a593Smuzhiyun struct snd_card *card = asihpi->card;
1726*4882a593Smuzhiyun struct snd_kcontrol_new snd_control;
1727*4882a593Smuzhiyun
1728*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
1729*4882a593Smuzhiyun snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1730*4882a593Smuzhiyun snd_control.info = snd_asihpi_aesebu_format_info;
1731*4882a593Smuzhiyun snd_control.get = snd_asihpi_aesebu_rx_format_get;
1732*4882a593Smuzhiyun snd_control.put = snd_asihpi_aesebu_rx_format_put;
1733*4882a593Smuzhiyun
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun if (ctl_add(card, &snd_control, asihpi) < 0)
1736*4882a593Smuzhiyun return -EINVAL;
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Status");
1739*4882a593Smuzhiyun snd_control.access =
1740*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
1741*4882a593Smuzhiyun snd_control.info = snd_asihpi_aesebu_rxstatus_info;
1742*4882a593Smuzhiyun snd_control.get = snd_asihpi_aesebu_rxstatus_get;
1743*4882a593Smuzhiyun
1744*4882a593Smuzhiyun return ctl_add(card, &snd_control, asihpi);
1745*4882a593Smuzhiyun }
1746*4882a593Smuzhiyun
snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1747*4882a593Smuzhiyun static int snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol *kcontrol,
1748*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol) {
1749*4882a593Smuzhiyun return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
1750*4882a593Smuzhiyun hpi_aesebu_transmitter_get_format);
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun
snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1753*4882a593Smuzhiyun static int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol,
1754*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol) {
1755*4882a593Smuzhiyun return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
1756*4882a593Smuzhiyun hpi_aesebu_transmitter_set_format);
1757*4882a593Smuzhiyun }
1758*4882a593Smuzhiyun
1759*4882a593Smuzhiyun
snd_asihpi_aesebu_tx_add(struct snd_card_asihpi * asihpi,struct hpi_control * hpi_ctl)1760*4882a593Smuzhiyun static int snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi,
1761*4882a593Smuzhiyun struct hpi_control *hpi_ctl)
1762*4882a593Smuzhiyun {
1763*4882a593Smuzhiyun struct snd_card *card = asihpi->card;
1764*4882a593Smuzhiyun struct snd_kcontrol_new snd_control;
1765*4882a593Smuzhiyun
1766*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
1767*4882a593Smuzhiyun snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1768*4882a593Smuzhiyun snd_control.info = snd_asihpi_aesebu_format_info;
1769*4882a593Smuzhiyun snd_control.get = snd_asihpi_aesebu_tx_format_get;
1770*4882a593Smuzhiyun snd_control.put = snd_asihpi_aesebu_tx_format_put;
1771*4882a593Smuzhiyun
1772*4882a593Smuzhiyun return ctl_add(card, &snd_control, asihpi);
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun
1775*4882a593Smuzhiyun /*------------------------------------------------------------
1776*4882a593Smuzhiyun Tuner controls
1777*4882a593Smuzhiyun ------------------------------------------------------------*/
1778*4882a593Smuzhiyun
1779*4882a593Smuzhiyun /* Gain */
1780*4882a593Smuzhiyun
snd_asihpi_tuner_gain_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1781*4882a593Smuzhiyun static int snd_asihpi_tuner_gain_info(struct snd_kcontrol *kcontrol,
1782*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
1783*4882a593Smuzhiyun {
1784*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1785*4882a593Smuzhiyun u16 err;
1786*4882a593Smuzhiyun short idx;
1787*4882a593Smuzhiyun u16 gain_range[3];
1788*4882a593Smuzhiyun
1789*4882a593Smuzhiyun for (idx = 0; idx < 3; idx++) {
1790*4882a593Smuzhiyun err = hpi_tuner_query_gain(h_control,
1791*4882a593Smuzhiyun idx, &gain_range[idx]);
1792*4882a593Smuzhiyun if (err != 0)
1793*4882a593Smuzhiyun return err;
1794*4882a593Smuzhiyun }
1795*4882a593Smuzhiyun
1796*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1797*4882a593Smuzhiyun uinfo->count = 1;
1798*4882a593Smuzhiyun uinfo->value.integer.min = ((int)gain_range[0]) / HPI_UNITS_PER_dB;
1799*4882a593Smuzhiyun uinfo->value.integer.max = ((int)gain_range[1]) / HPI_UNITS_PER_dB;
1800*4882a593Smuzhiyun uinfo->value.integer.step = ((int) gain_range[2]) / HPI_UNITS_PER_dB;
1801*4882a593Smuzhiyun return 0;
1802*4882a593Smuzhiyun }
1803*4882a593Smuzhiyun
snd_asihpi_tuner_gain_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1804*4882a593Smuzhiyun static int snd_asihpi_tuner_gain_get(struct snd_kcontrol *kcontrol,
1805*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1806*4882a593Smuzhiyun {
1807*4882a593Smuzhiyun /*
1808*4882a593Smuzhiyun struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1809*4882a593Smuzhiyun */
1810*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1811*4882a593Smuzhiyun short gain;
1812*4882a593Smuzhiyun
1813*4882a593Smuzhiyun hpi_handle_error(hpi_tuner_get_gain(h_control, &gain));
1814*4882a593Smuzhiyun ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;
1815*4882a593Smuzhiyun
1816*4882a593Smuzhiyun return 0;
1817*4882a593Smuzhiyun }
1818*4882a593Smuzhiyun
snd_asihpi_tuner_gain_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1819*4882a593Smuzhiyun static int snd_asihpi_tuner_gain_put(struct snd_kcontrol *kcontrol,
1820*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1821*4882a593Smuzhiyun {
1822*4882a593Smuzhiyun /*
1823*4882a593Smuzhiyun struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1824*4882a593Smuzhiyun */
1825*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1826*4882a593Smuzhiyun short gain;
1827*4882a593Smuzhiyun
1828*4882a593Smuzhiyun gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
1829*4882a593Smuzhiyun hpi_handle_error(hpi_tuner_set_gain(h_control, gain));
1830*4882a593Smuzhiyun
1831*4882a593Smuzhiyun return 1;
1832*4882a593Smuzhiyun }
1833*4882a593Smuzhiyun
1834*4882a593Smuzhiyun /* Band */
1835*4882a593Smuzhiyun
asihpi_tuner_band_query(struct snd_kcontrol * kcontrol,u16 * band_list,u32 len)1836*4882a593Smuzhiyun static int asihpi_tuner_band_query(struct snd_kcontrol *kcontrol,
1837*4882a593Smuzhiyun u16 *band_list, u32 len) {
1838*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1839*4882a593Smuzhiyun u16 err = 0;
1840*4882a593Smuzhiyun u32 i;
1841*4882a593Smuzhiyun
1842*4882a593Smuzhiyun for (i = 0; i < len; i++) {
1843*4882a593Smuzhiyun err = hpi_tuner_query_band(
1844*4882a593Smuzhiyun h_control, i, &band_list[i]);
1845*4882a593Smuzhiyun if (err != 0)
1846*4882a593Smuzhiyun break;
1847*4882a593Smuzhiyun }
1848*4882a593Smuzhiyun
1849*4882a593Smuzhiyun if (err && (err != HPI_ERROR_INVALID_OBJ_INDEX))
1850*4882a593Smuzhiyun return -EIO;
1851*4882a593Smuzhiyun
1852*4882a593Smuzhiyun return i;
1853*4882a593Smuzhiyun }
1854*4882a593Smuzhiyun
snd_asihpi_tuner_band_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1855*4882a593Smuzhiyun static int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol,
1856*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
1857*4882a593Smuzhiyun {
1858*4882a593Smuzhiyun u16 tuner_bands[HPI_TUNER_BAND_LAST];
1859*4882a593Smuzhiyun int num_bands = 0;
1860*4882a593Smuzhiyun
1861*4882a593Smuzhiyun num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1862*4882a593Smuzhiyun HPI_TUNER_BAND_LAST);
1863*4882a593Smuzhiyun
1864*4882a593Smuzhiyun if (num_bands < 0)
1865*4882a593Smuzhiyun return num_bands;
1866*4882a593Smuzhiyun
1867*4882a593Smuzhiyun return snd_ctl_enum_info(uinfo, 1, num_bands, asihpi_tuner_band_names);
1868*4882a593Smuzhiyun }
1869*4882a593Smuzhiyun
snd_asihpi_tuner_band_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1870*4882a593Smuzhiyun static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,
1871*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1872*4882a593Smuzhiyun {
1873*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1874*4882a593Smuzhiyun /*
1875*4882a593Smuzhiyun struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1876*4882a593Smuzhiyun */
1877*4882a593Smuzhiyun u16 band, idx;
1878*4882a593Smuzhiyun u16 tuner_bands[HPI_TUNER_BAND_LAST];
1879*4882a593Smuzhiyun __always_unused u32 num_bands;
1880*4882a593Smuzhiyun
1881*4882a593Smuzhiyun num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1882*4882a593Smuzhiyun HPI_TUNER_BAND_LAST);
1883*4882a593Smuzhiyun
1884*4882a593Smuzhiyun hpi_handle_error(hpi_tuner_get_band(h_control, &band));
1885*4882a593Smuzhiyun
1886*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = -1;
1887*4882a593Smuzhiyun for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)
1888*4882a593Smuzhiyun if (tuner_bands[idx] == band) {
1889*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = idx;
1890*4882a593Smuzhiyun break;
1891*4882a593Smuzhiyun }
1892*4882a593Smuzhiyun
1893*4882a593Smuzhiyun return 0;
1894*4882a593Smuzhiyun }
1895*4882a593Smuzhiyun
snd_asihpi_tuner_band_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1896*4882a593Smuzhiyun static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,
1897*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1898*4882a593Smuzhiyun {
1899*4882a593Smuzhiyun /*
1900*4882a593Smuzhiyun struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
1901*4882a593Smuzhiyun */
1902*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1903*4882a593Smuzhiyun unsigned int idx;
1904*4882a593Smuzhiyun u16 band;
1905*4882a593Smuzhiyun u16 tuner_bands[HPI_TUNER_BAND_LAST];
1906*4882a593Smuzhiyun __always_unused u32 num_bands;
1907*4882a593Smuzhiyun
1908*4882a593Smuzhiyun num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1909*4882a593Smuzhiyun HPI_TUNER_BAND_LAST);
1910*4882a593Smuzhiyun
1911*4882a593Smuzhiyun idx = ucontrol->value.enumerated.item[0];
1912*4882a593Smuzhiyun if (idx >= ARRAY_SIZE(tuner_bands))
1913*4882a593Smuzhiyun idx = ARRAY_SIZE(tuner_bands) - 1;
1914*4882a593Smuzhiyun band = tuner_bands[idx];
1915*4882a593Smuzhiyun hpi_handle_error(hpi_tuner_set_band(h_control, band));
1916*4882a593Smuzhiyun
1917*4882a593Smuzhiyun return 1;
1918*4882a593Smuzhiyun }
1919*4882a593Smuzhiyun
1920*4882a593Smuzhiyun /* Freq */
1921*4882a593Smuzhiyun
snd_asihpi_tuner_freq_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1922*4882a593Smuzhiyun static int snd_asihpi_tuner_freq_info(struct snd_kcontrol *kcontrol,
1923*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
1924*4882a593Smuzhiyun {
1925*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1926*4882a593Smuzhiyun u16 err;
1927*4882a593Smuzhiyun u16 tuner_bands[HPI_TUNER_BAND_LAST];
1928*4882a593Smuzhiyun u16 num_bands = 0, band_iter, idx;
1929*4882a593Smuzhiyun u32 freq_range[3], temp_freq_range[3];
1930*4882a593Smuzhiyun
1931*4882a593Smuzhiyun num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
1932*4882a593Smuzhiyun HPI_TUNER_BAND_LAST);
1933*4882a593Smuzhiyun
1934*4882a593Smuzhiyun freq_range[0] = INT_MAX;
1935*4882a593Smuzhiyun freq_range[1] = 0;
1936*4882a593Smuzhiyun freq_range[2] = INT_MAX;
1937*4882a593Smuzhiyun
1938*4882a593Smuzhiyun for (band_iter = 0; band_iter < num_bands; band_iter++) {
1939*4882a593Smuzhiyun for (idx = 0; idx < 3; idx++) {
1940*4882a593Smuzhiyun err = hpi_tuner_query_frequency(h_control,
1941*4882a593Smuzhiyun idx, tuner_bands[band_iter],
1942*4882a593Smuzhiyun &temp_freq_range[idx]);
1943*4882a593Smuzhiyun if (err != 0)
1944*4882a593Smuzhiyun return err;
1945*4882a593Smuzhiyun }
1946*4882a593Smuzhiyun
1947*4882a593Smuzhiyun /* skip band with bogus stepping */
1948*4882a593Smuzhiyun if (temp_freq_range[2] <= 0)
1949*4882a593Smuzhiyun continue;
1950*4882a593Smuzhiyun
1951*4882a593Smuzhiyun if (temp_freq_range[0] < freq_range[0])
1952*4882a593Smuzhiyun freq_range[0] = temp_freq_range[0];
1953*4882a593Smuzhiyun if (temp_freq_range[1] > freq_range[1])
1954*4882a593Smuzhiyun freq_range[1] = temp_freq_range[1];
1955*4882a593Smuzhiyun if (temp_freq_range[2] < freq_range[2])
1956*4882a593Smuzhiyun freq_range[2] = temp_freq_range[2];
1957*4882a593Smuzhiyun }
1958*4882a593Smuzhiyun
1959*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1960*4882a593Smuzhiyun uinfo->count = 1;
1961*4882a593Smuzhiyun uinfo->value.integer.min = ((int)freq_range[0]);
1962*4882a593Smuzhiyun uinfo->value.integer.max = ((int)freq_range[1]);
1963*4882a593Smuzhiyun uinfo->value.integer.step = ((int)freq_range[2]);
1964*4882a593Smuzhiyun return 0;
1965*4882a593Smuzhiyun }
1966*4882a593Smuzhiyun
snd_asihpi_tuner_freq_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1967*4882a593Smuzhiyun static int snd_asihpi_tuner_freq_get(struct snd_kcontrol *kcontrol,
1968*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1969*4882a593Smuzhiyun {
1970*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1971*4882a593Smuzhiyun u32 freq;
1972*4882a593Smuzhiyun
1973*4882a593Smuzhiyun hpi_handle_error(hpi_tuner_get_frequency(h_control, &freq));
1974*4882a593Smuzhiyun ucontrol->value.integer.value[0] = freq;
1975*4882a593Smuzhiyun
1976*4882a593Smuzhiyun return 0;
1977*4882a593Smuzhiyun }
1978*4882a593Smuzhiyun
snd_asihpi_tuner_freq_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1979*4882a593Smuzhiyun static int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol,
1980*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1981*4882a593Smuzhiyun {
1982*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
1983*4882a593Smuzhiyun u32 freq;
1984*4882a593Smuzhiyun
1985*4882a593Smuzhiyun freq = ucontrol->value.integer.value[0];
1986*4882a593Smuzhiyun hpi_handle_error(hpi_tuner_set_frequency(h_control, freq));
1987*4882a593Smuzhiyun
1988*4882a593Smuzhiyun return 1;
1989*4882a593Smuzhiyun }
1990*4882a593Smuzhiyun
1991*4882a593Smuzhiyun /* Tuner control group initializer */
snd_asihpi_tuner_add(struct snd_card_asihpi * asihpi,struct hpi_control * hpi_ctl)1992*4882a593Smuzhiyun static int snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
1993*4882a593Smuzhiyun struct hpi_control *hpi_ctl)
1994*4882a593Smuzhiyun {
1995*4882a593Smuzhiyun struct snd_card *card = asihpi->card;
1996*4882a593Smuzhiyun struct snd_kcontrol_new snd_control;
1997*4882a593Smuzhiyun
1998*4882a593Smuzhiyun snd_control.private_value = hpi_ctl->h_control;
1999*4882a593Smuzhiyun snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2000*4882a593Smuzhiyun
2001*4882a593Smuzhiyun if (!hpi_tuner_get_gain(hpi_ctl->h_control, NULL)) {
2002*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Gain");
2003*4882a593Smuzhiyun snd_control.info = snd_asihpi_tuner_gain_info;
2004*4882a593Smuzhiyun snd_control.get = snd_asihpi_tuner_gain_get;
2005*4882a593Smuzhiyun snd_control.put = snd_asihpi_tuner_gain_put;
2006*4882a593Smuzhiyun
2007*4882a593Smuzhiyun if (ctl_add(card, &snd_control, asihpi) < 0)
2008*4882a593Smuzhiyun return -EINVAL;
2009*4882a593Smuzhiyun }
2010*4882a593Smuzhiyun
2011*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Band");
2012*4882a593Smuzhiyun snd_control.info = snd_asihpi_tuner_band_info;
2013*4882a593Smuzhiyun snd_control.get = snd_asihpi_tuner_band_get;
2014*4882a593Smuzhiyun snd_control.put = snd_asihpi_tuner_band_put;
2015*4882a593Smuzhiyun
2016*4882a593Smuzhiyun if (ctl_add(card, &snd_control, asihpi) < 0)
2017*4882a593Smuzhiyun return -EINVAL;
2018*4882a593Smuzhiyun
2019*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Freq");
2020*4882a593Smuzhiyun snd_control.info = snd_asihpi_tuner_freq_info;
2021*4882a593Smuzhiyun snd_control.get = snd_asihpi_tuner_freq_get;
2022*4882a593Smuzhiyun snd_control.put = snd_asihpi_tuner_freq_put;
2023*4882a593Smuzhiyun
2024*4882a593Smuzhiyun return ctl_add(card, &snd_control, asihpi);
2025*4882a593Smuzhiyun }
2026*4882a593Smuzhiyun
2027*4882a593Smuzhiyun /*------------------------------------------------------------
2028*4882a593Smuzhiyun Meter controls
2029*4882a593Smuzhiyun ------------------------------------------------------------*/
snd_asihpi_meter_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2030*4882a593Smuzhiyun static int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol,
2031*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
2032*4882a593Smuzhiyun {
2033*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2034*4882a593Smuzhiyun u32 count;
2035*4882a593Smuzhiyun u16 err;
2036*4882a593Smuzhiyun err = hpi_meter_query_channels(h_control, &count);
2037*4882a593Smuzhiyun if (err)
2038*4882a593Smuzhiyun count = HPI_MAX_CHANNELS;
2039*4882a593Smuzhiyun
2040*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2041*4882a593Smuzhiyun uinfo->count = count;
2042*4882a593Smuzhiyun uinfo->value.integer.min = 0;
2043*4882a593Smuzhiyun uinfo->value.integer.max = 0x7FFFFFFF;
2044*4882a593Smuzhiyun return 0;
2045*4882a593Smuzhiyun }
2046*4882a593Smuzhiyun
2047*4882a593Smuzhiyun /* linear values for 10dB steps */
2048*4882a593Smuzhiyun static const int log2lin[] = {
2049*4882a593Smuzhiyun 0x7FFFFFFF, /* 0dB */
2050*4882a593Smuzhiyun 679093956,
2051*4882a593Smuzhiyun 214748365,
2052*4882a593Smuzhiyun 67909396,
2053*4882a593Smuzhiyun 21474837,
2054*4882a593Smuzhiyun 6790940,
2055*4882a593Smuzhiyun 2147484, /* -60dB */
2056*4882a593Smuzhiyun 679094,
2057*4882a593Smuzhiyun 214748, /* -80 */
2058*4882a593Smuzhiyun 67909,
2059*4882a593Smuzhiyun 21475, /* -100 */
2060*4882a593Smuzhiyun 6791,
2061*4882a593Smuzhiyun 2147,
2062*4882a593Smuzhiyun 679,
2063*4882a593Smuzhiyun 214,
2064*4882a593Smuzhiyun 68,
2065*4882a593Smuzhiyun 21,
2066*4882a593Smuzhiyun 7,
2067*4882a593Smuzhiyun 2
2068*4882a593Smuzhiyun };
2069*4882a593Smuzhiyun
snd_asihpi_meter_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2070*4882a593Smuzhiyun static int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol,
2071*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
2072*4882a593Smuzhiyun {
2073*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2074*4882a593Smuzhiyun short an_gain_mB[HPI_MAX_CHANNELS], i;
2075*4882a593Smuzhiyun u16 err;
2076*4882a593Smuzhiyun
2077*4882a593Smuzhiyun err = hpi_meter_get_peak(h_control, an_gain_mB);
2078*4882a593Smuzhiyun
2079*4882a593Smuzhiyun for (i = 0; i < HPI_MAX_CHANNELS; i++) {
2080*4882a593Smuzhiyun if (err) {
2081*4882a593Smuzhiyun ucontrol->value.integer.value[i] = 0;
2082*4882a593Smuzhiyun } else if (an_gain_mB[i] >= 0) {
2083*4882a593Smuzhiyun ucontrol->value.integer.value[i] =
2084*4882a593Smuzhiyun an_gain_mB[i] << 16;
2085*4882a593Smuzhiyun } else {
2086*4882a593Smuzhiyun /* -ve is log value in millibels < -60dB,
2087*4882a593Smuzhiyun * convert to (roughly!) linear,
2088*4882a593Smuzhiyun */
2089*4882a593Smuzhiyun ucontrol->value.integer.value[i] =
2090*4882a593Smuzhiyun log2lin[an_gain_mB[i] / -1000];
2091*4882a593Smuzhiyun }
2092*4882a593Smuzhiyun }
2093*4882a593Smuzhiyun return 0;
2094*4882a593Smuzhiyun }
2095*4882a593Smuzhiyun
snd_asihpi_meter_add(struct snd_card_asihpi * asihpi,struct hpi_control * hpi_ctl,int subidx)2096*4882a593Smuzhiyun static int snd_asihpi_meter_add(struct snd_card_asihpi *asihpi,
2097*4882a593Smuzhiyun struct hpi_control *hpi_ctl, int subidx)
2098*4882a593Smuzhiyun {
2099*4882a593Smuzhiyun struct snd_card *card = asihpi->card;
2100*4882a593Smuzhiyun struct snd_kcontrol_new snd_control;
2101*4882a593Smuzhiyun
2102*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Meter");
2103*4882a593Smuzhiyun snd_control.access =
2104*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2105*4882a593Smuzhiyun snd_control.info = snd_asihpi_meter_info;
2106*4882a593Smuzhiyun snd_control.get = snd_asihpi_meter_get;
2107*4882a593Smuzhiyun
2108*4882a593Smuzhiyun snd_control.index = subidx;
2109*4882a593Smuzhiyun
2110*4882a593Smuzhiyun return ctl_add(card, &snd_control, asihpi);
2111*4882a593Smuzhiyun }
2112*4882a593Smuzhiyun
2113*4882a593Smuzhiyun /*------------------------------------------------------------
2114*4882a593Smuzhiyun Multiplexer controls
2115*4882a593Smuzhiyun ------------------------------------------------------------*/
snd_card_asihpi_mux_count_sources(struct snd_kcontrol * snd_control)2116*4882a593Smuzhiyun static int snd_card_asihpi_mux_count_sources(struct snd_kcontrol *snd_control)
2117*4882a593Smuzhiyun {
2118*4882a593Smuzhiyun u32 h_control = snd_control->private_value;
2119*4882a593Smuzhiyun struct hpi_control hpi_ctl;
2120*4882a593Smuzhiyun int s, err;
2121*4882a593Smuzhiyun for (s = 0; s < 32; s++) {
2122*4882a593Smuzhiyun err = hpi_multiplexer_query_source(h_control, s,
2123*4882a593Smuzhiyun &hpi_ctl.
2124*4882a593Smuzhiyun src_node_type,
2125*4882a593Smuzhiyun &hpi_ctl.
2126*4882a593Smuzhiyun src_node_index);
2127*4882a593Smuzhiyun if (err)
2128*4882a593Smuzhiyun break;
2129*4882a593Smuzhiyun }
2130*4882a593Smuzhiyun return s;
2131*4882a593Smuzhiyun }
2132*4882a593Smuzhiyun
snd_asihpi_mux_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2133*4882a593Smuzhiyun static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
2134*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
2135*4882a593Smuzhiyun {
2136*4882a593Smuzhiyun u16 src_node_type, src_node_index;
2137*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2138*4882a593Smuzhiyun
2139*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2140*4882a593Smuzhiyun uinfo->count = 1;
2141*4882a593Smuzhiyun uinfo->value.enumerated.items =
2142*4882a593Smuzhiyun snd_card_asihpi_mux_count_sources(kcontrol);
2143*4882a593Smuzhiyun
2144*4882a593Smuzhiyun if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2145*4882a593Smuzhiyun uinfo->value.enumerated.item =
2146*4882a593Smuzhiyun uinfo->value.enumerated.items - 1;
2147*4882a593Smuzhiyun
2148*4882a593Smuzhiyun hpi_multiplexer_query_source(h_control,
2149*4882a593Smuzhiyun uinfo->value.enumerated.item,
2150*4882a593Smuzhiyun &src_node_type, &src_node_index);
2151*4882a593Smuzhiyun
2152*4882a593Smuzhiyun sprintf(uinfo->value.enumerated.name, "%s %d",
2153*4882a593Smuzhiyun asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE],
2154*4882a593Smuzhiyun src_node_index);
2155*4882a593Smuzhiyun return 0;
2156*4882a593Smuzhiyun }
2157*4882a593Smuzhiyun
snd_asihpi_mux_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2158*4882a593Smuzhiyun static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,
2159*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
2160*4882a593Smuzhiyun {
2161*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2162*4882a593Smuzhiyun u16 source_type, source_index;
2163*4882a593Smuzhiyun u16 src_node_type, src_node_index;
2164*4882a593Smuzhiyun int s;
2165*4882a593Smuzhiyun
2166*4882a593Smuzhiyun hpi_handle_error(hpi_multiplexer_get_source(h_control,
2167*4882a593Smuzhiyun &source_type, &source_index));
2168*4882a593Smuzhiyun /* Should cache this search result! */
2169*4882a593Smuzhiyun for (s = 0; s < 256; s++) {
2170*4882a593Smuzhiyun if (hpi_multiplexer_query_source(h_control, s,
2171*4882a593Smuzhiyun &src_node_type, &src_node_index))
2172*4882a593Smuzhiyun break;
2173*4882a593Smuzhiyun
2174*4882a593Smuzhiyun if ((source_type == src_node_type)
2175*4882a593Smuzhiyun && (source_index == src_node_index)) {
2176*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = s;
2177*4882a593Smuzhiyun return 0;
2178*4882a593Smuzhiyun }
2179*4882a593Smuzhiyun }
2180*4882a593Smuzhiyun snd_printd(KERN_WARNING
2181*4882a593Smuzhiyun "Control %x failed to match mux source %hu %hu\n",
2182*4882a593Smuzhiyun h_control, source_type, source_index);
2183*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = 0;
2184*4882a593Smuzhiyun return 0;
2185*4882a593Smuzhiyun }
2186*4882a593Smuzhiyun
snd_asihpi_mux_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2187*4882a593Smuzhiyun static int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol,
2188*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
2189*4882a593Smuzhiyun {
2190*4882a593Smuzhiyun int change;
2191*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2192*4882a593Smuzhiyun u16 source_type, source_index;
2193*4882a593Smuzhiyun u16 e;
2194*4882a593Smuzhiyun
2195*4882a593Smuzhiyun change = 1;
2196*4882a593Smuzhiyun
2197*4882a593Smuzhiyun e = hpi_multiplexer_query_source(h_control,
2198*4882a593Smuzhiyun ucontrol->value.enumerated.item[0],
2199*4882a593Smuzhiyun &source_type, &source_index);
2200*4882a593Smuzhiyun if (!e)
2201*4882a593Smuzhiyun hpi_handle_error(
2202*4882a593Smuzhiyun hpi_multiplexer_set_source(h_control,
2203*4882a593Smuzhiyun source_type, source_index));
2204*4882a593Smuzhiyun return change;
2205*4882a593Smuzhiyun }
2206*4882a593Smuzhiyun
2207*4882a593Smuzhiyun
snd_asihpi_mux_add(struct snd_card_asihpi * asihpi,struct hpi_control * hpi_ctl)2208*4882a593Smuzhiyun static int snd_asihpi_mux_add(struct snd_card_asihpi *asihpi,
2209*4882a593Smuzhiyun struct hpi_control *hpi_ctl)
2210*4882a593Smuzhiyun {
2211*4882a593Smuzhiyun struct snd_card *card = asihpi->card;
2212*4882a593Smuzhiyun struct snd_kcontrol_new snd_control;
2213*4882a593Smuzhiyun
2214*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Route");
2215*4882a593Smuzhiyun snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2216*4882a593Smuzhiyun snd_control.info = snd_asihpi_mux_info;
2217*4882a593Smuzhiyun snd_control.get = snd_asihpi_mux_get;
2218*4882a593Smuzhiyun snd_control.put = snd_asihpi_mux_put;
2219*4882a593Smuzhiyun
2220*4882a593Smuzhiyun return ctl_add(card, &snd_control, asihpi);
2221*4882a593Smuzhiyun
2222*4882a593Smuzhiyun }
2223*4882a593Smuzhiyun
2224*4882a593Smuzhiyun /*------------------------------------------------------------
2225*4882a593Smuzhiyun Channel mode controls
2226*4882a593Smuzhiyun ------------------------------------------------------------*/
snd_asihpi_cmode_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2227*4882a593Smuzhiyun static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
2228*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
2229*4882a593Smuzhiyun {
2230*4882a593Smuzhiyun static const char * const mode_names[HPI_CHANNEL_MODE_LAST + 1] = {
2231*4882a593Smuzhiyun "invalid",
2232*4882a593Smuzhiyun "Normal", "Swap",
2233*4882a593Smuzhiyun "From Left", "From Right",
2234*4882a593Smuzhiyun "To Left", "To Right"
2235*4882a593Smuzhiyun };
2236*4882a593Smuzhiyun
2237*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2238*4882a593Smuzhiyun u16 mode;
2239*4882a593Smuzhiyun int i;
2240*4882a593Smuzhiyun const char *mapped_names[6];
2241*4882a593Smuzhiyun int valid_modes = 0;
2242*4882a593Smuzhiyun
2243*4882a593Smuzhiyun /* HPI channel mode values can be from 1 to 6
2244*4882a593Smuzhiyun Some adapters only support a contiguous subset
2245*4882a593Smuzhiyun */
2246*4882a593Smuzhiyun for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)
2247*4882a593Smuzhiyun if (!hpi_channel_mode_query_mode(
2248*4882a593Smuzhiyun h_control, i, &mode)) {
2249*4882a593Smuzhiyun mapped_names[valid_modes] = mode_names[mode];
2250*4882a593Smuzhiyun valid_modes++;
2251*4882a593Smuzhiyun }
2252*4882a593Smuzhiyun
2253*4882a593Smuzhiyun if (!valid_modes)
2254*4882a593Smuzhiyun return -EINVAL;
2255*4882a593Smuzhiyun
2256*4882a593Smuzhiyun return snd_ctl_enum_info(uinfo, 1, valid_modes, mapped_names);
2257*4882a593Smuzhiyun }
2258*4882a593Smuzhiyun
snd_asihpi_cmode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2259*4882a593Smuzhiyun static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,
2260*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
2261*4882a593Smuzhiyun {
2262*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2263*4882a593Smuzhiyun u16 mode;
2264*4882a593Smuzhiyun
2265*4882a593Smuzhiyun if (hpi_channel_mode_get(h_control, &mode))
2266*4882a593Smuzhiyun mode = 1;
2267*4882a593Smuzhiyun
2268*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = mode - 1;
2269*4882a593Smuzhiyun
2270*4882a593Smuzhiyun return 0;
2271*4882a593Smuzhiyun }
2272*4882a593Smuzhiyun
snd_asihpi_cmode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2273*4882a593Smuzhiyun static int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol,
2274*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
2275*4882a593Smuzhiyun {
2276*4882a593Smuzhiyun int change;
2277*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2278*4882a593Smuzhiyun
2279*4882a593Smuzhiyun change = 1;
2280*4882a593Smuzhiyun
2281*4882a593Smuzhiyun hpi_handle_error(hpi_channel_mode_set(h_control,
2282*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] + 1));
2283*4882a593Smuzhiyun return change;
2284*4882a593Smuzhiyun }
2285*4882a593Smuzhiyun
2286*4882a593Smuzhiyun
snd_asihpi_cmode_add(struct snd_card_asihpi * asihpi,struct hpi_control * hpi_ctl)2287*4882a593Smuzhiyun static int snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
2288*4882a593Smuzhiyun struct hpi_control *hpi_ctl)
2289*4882a593Smuzhiyun {
2290*4882a593Smuzhiyun struct snd_card *card = asihpi->card;
2291*4882a593Smuzhiyun struct snd_kcontrol_new snd_control;
2292*4882a593Smuzhiyun
2293*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Mode");
2294*4882a593Smuzhiyun snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
2295*4882a593Smuzhiyun snd_control.info = snd_asihpi_cmode_info;
2296*4882a593Smuzhiyun snd_control.get = snd_asihpi_cmode_get;
2297*4882a593Smuzhiyun snd_control.put = snd_asihpi_cmode_put;
2298*4882a593Smuzhiyun
2299*4882a593Smuzhiyun return ctl_add(card, &snd_control, asihpi);
2300*4882a593Smuzhiyun }
2301*4882a593Smuzhiyun
2302*4882a593Smuzhiyun /*------------------------------------------------------------
2303*4882a593Smuzhiyun Sampleclock source controls
2304*4882a593Smuzhiyun ------------------------------------------------------------*/
2305*4882a593Smuzhiyun static const char * const sampleclock_sources[] = {
2306*4882a593Smuzhiyun "N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
2307*4882a593Smuzhiyun "SMPTE", "Digital1", "Auto", "Network", "Invalid",
2308*4882a593Smuzhiyun "Prev Module", "BLU-Link",
2309*4882a593Smuzhiyun "Digital2", "Digital3", "Digital4", "Digital5",
2310*4882a593Smuzhiyun "Digital6", "Digital7", "Digital8"};
2311*4882a593Smuzhiyun
2312*4882a593Smuzhiyun /* Number of strings must match expected enumerated values */
2313*4882a593Smuzhiyun compile_time_assert(
2314*4882a593Smuzhiyun (ARRAY_SIZE(sampleclock_sources) == MAX_CLOCKSOURCES),
2315*4882a593Smuzhiyun assert_sampleclock_sources_size);
2316*4882a593Smuzhiyun
snd_asihpi_clksrc_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2317*4882a593Smuzhiyun static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
2318*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
2319*4882a593Smuzhiyun {
2320*4882a593Smuzhiyun struct snd_card_asihpi *asihpi =
2321*4882a593Smuzhiyun (struct snd_card_asihpi *)(kcontrol->private_data);
2322*4882a593Smuzhiyun struct clk_cache *clkcache = &asihpi->cc;
2323*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2324*4882a593Smuzhiyun uinfo->count = 1;
2325*4882a593Smuzhiyun uinfo->value.enumerated.items = clkcache->count;
2326*4882a593Smuzhiyun
2327*4882a593Smuzhiyun if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2328*4882a593Smuzhiyun uinfo->value.enumerated.item =
2329*4882a593Smuzhiyun uinfo->value.enumerated.items - 1;
2330*4882a593Smuzhiyun
2331*4882a593Smuzhiyun strcpy(uinfo->value.enumerated.name,
2332*4882a593Smuzhiyun clkcache->s[uinfo->value.enumerated.item].name);
2333*4882a593Smuzhiyun return 0;
2334*4882a593Smuzhiyun }
2335*4882a593Smuzhiyun
snd_asihpi_clksrc_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2336*4882a593Smuzhiyun static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,
2337*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
2338*4882a593Smuzhiyun {
2339*4882a593Smuzhiyun struct snd_card_asihpi *asihpi =
2340*4882a593Smuzhiyun (struct snd_card_asihpi *)(kcontrol->private_data);
2341*4882a593Smuzhiyun struct clk_cache *clkcache = &asihpi->cc;
2342*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2343*4882a593Smuzhiyun u16 source, srcindex = 0;
2344*4882a593Smuzhiyun int i;
2345*4882a593Smuzhiyun
2346*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = 0;
2347*4882a593Smuzhiyun if (hpi_sample_clock_get_source(h_control, &source))
2348*4882a593Smuzhiyun source = 0;
2349*4882a593Smuzhiyun
2350*4882a593Smuzhiyun if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2351*4882a593Smuzhiyun if (hpi_sample_clock_get_source_index(h_control, &srcindex))
2352*4882a593Smuzhiyun srcindex = 0;
2353*4882a593Smuzhiyun
2354*4882a593Smuzhiyun for (i = 0; i < clkcache->count; i++)
2355*4882a593Smuzhiyun if ((clkcache->s[i].source == source) &&
2356*4882a593Smuzhiyun (clkcache->s[i].index == srcindex))
2357*4882a593Smuzhiyun break;
2358*4882a593Smuzhiyun
2359*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = i;
2360*4882a593Smuzhiyun
2361*4882a593Smuzhiyun return 0;
2362*4882a593Smuzhiyun }
2363*4882a593Smuzhiyun
snd_asihpi_clksrc_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2364*4882a593Smuzhiyun static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,
2365*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
2366*4882a593Smuzhiyun {
2367*4882a593Smuzhiyun struct snd_card_asihpi *asihpi =
2368*4882a593Smuzhiyun (struct snd_card_asihpi *)(kcontrol->private_data);
2369*4882a593Smuzhiyun struct clk_cache *clkcache = &asihpi->cc;
2370*4882a593Smuzhiyun unsigned int item;
2371*4882a593Smuzhiyun int change;
2372*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2373*4882a593Smuzhiyun
2374*4882a593Smuzhiyun change = 1;
2375*4882a593Smuzhiyun item = ucontrol->value.enumerated.item[0];
2376*4882a593Smuzhiyun if (item >= clkcache->count)
2377*4882a593Smuzhiyun item = clkcache->count-1;
2378*4882a593Smuzhiyun
2379*4882a593Smuzhiyun hpi_handle_error(hpi_sample_clock_set_source(
2380*4882a593Smuzhiyun h_control, clkcache->s[item].source));
2381*4882a593Smuzhiyun
2382*4882a593Smuzhiyun if (clkcache->s[item].source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2383*4882a593Smuzhiyun hpi_handle_error(hpi_sample_clock_set_source_index(
2384*4882a593Smuzhiyun h_control, clkcache->s[item].index));
2385*4882a593Smuzhiyun return change;
2386*4882a593Smuzhiyun }
2387*4882a593Smuzhiyun
2388*4882a593Smuzhiyun /*------------------------------------------------------------
2389*4882a593Smuzhiyun Clkrate controls
2390*4882a593Smuzhiyun ------------------------------------------------------------*/
2391*4882a593Smuzhiyun /* Need to change this to enumerated control with list of rates */
snd_asihpi_clklocal_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2392*4882a593Smuzhiyun static int snd_asihpi_clklocal_info(struct snd_kcontrol *kcontrol,
2393*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
2394*4882a593Smuzhiyun {
2395*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2396*4882a593Smuzhiyun uinfo->count = 1;
2397*4882a593Smuzhiyun uinfo->value.integer.min = 8000;
2398*4882a593Smuzhiyun uinfo->value.integer.max = 192000;
2399*4882a593Smuzhiyun uinfo->value.integer.step = 100;
2400*4882a593Smuzhiyun
2401*4882a593Smuzhiyun return 0;
2402*4882a593Smuzhiyun }
2403*4882a593Smuzhiyun
snd_asihpi_clklocal_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2404*4882a593Smuzhiyun static int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol,
2405*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
2406*4882a593Smuzhiyun {
2407*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2408*4882a593Smuzhiyun u32 rate;
2409*4882a593Smuzhiyun u16 e;
2410*4882a593Smuzhiyun
2411*4882a593Smuzhiyun e = hpi_sample_clock_get_local_rate(h_control, &rate);
2412*4882a593Smuzhiyun if (!e)
2413*4882a593Smuzhiyun ucontrol->value.integer.value[0] = rate;
2414*4882a593Smuzhiyun else
2415*4882a593Smuzhiyun ucontrol->value.integer.value[0] = 0;
2416*4882a593Smuzhiyun return 0;
2417*4882a593Smuzhiyun }
2418*4882a593Smuzhiyun
snd_asihpi_clklocal_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2419*4882a593Smuzhiyun static int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol,
2420*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
2421*4882a593Smuzhiyun {
2422*4882a593Smuzhiyun int change;
2423*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2424*4882a593Smuzhiyun
2425*4882a593Smuzhiyun /* change = asihpi->mixer_clkrate[addr][0] != left ||
2426*4882a593Smuzhiyun asihpi->mixer_clkrate[addr][1] != right;
2427*4882a593Smuzhiyun */
2428*4882a593Smuzhiyun change = 1;
2429*4882a593Smuzhiyun hpi_handle_error(hpi_sample_clock_set_local_rate(h_control,
2430*4882a593Smuzhiyun ucontrol->value.integer.value[0]));
2431*4882a593Smuzhiyun return change;
2432*4882a593Smuzhiyun }
2433*4882a593Smuzhiyun
snd_asihpi_clkrate_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2434*4882a593Smuzhiyun static int snd_asihpi_clkrate_info(struct snd_kcontrol *kcontrol,
2435*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
2436*4882a593Smuzhiyun {
2437*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2438*4882a593Smuzhiyun uinfo->count = 1;
2439*4882a593Smuzhiyun uinfo->value.integer.min = 8000;
2440*4882a593Smuzhiyun uinfo->value.integer.max = 192000;
2441*4882a593Smuzhiyun uinfo->value.integer.step = 100;
2442*4882a593Smuzhiyun
2443*4882a593Smuzhiyun return 0;
2444*4882a593Smuzhiyun }
2445*4882a593Smuzhiyun
snd_asihpi_clkrate_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2446*4882a593Smuzhiyun static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,
2447*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
2448*4882a593Smuzhiyun {
2449*4882a593Smuzhiyun u32 h_control = kcontrol->private_value;
2450*4882a593Smuzhiyun u32 rate;
2451*4882a593Smuzhiyun u16 e;
2452*4882a593Smuzhiyun
2453*4882a593Smuzhiyun e = hpi_sample_clock_get_sample_rate(h_control, &rate);
2454*4882a593Smuzhiyun if (!e)
2455*4882a593Smuzhiyun ucontrol->value.integer.value[0] = rate;
2456*4882a593Smuzhiyun else
2457*4882a593Smuzhiyun ucontrol->value.integer.value[0] = 0;
2458*4882a593Smuzhiyun return 0;
2459*4882a593Smuzhiyun }
2460*4882a593Smuzhiyun
snd_asihpi_sampleclock_add(struct snd_card_asihpi * asihpi,struct hpi_control * hpi_ctl)2461*4882a593Smuzhiyun static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
2462*4882a593Smuzhiyun struct hpi_control *hpi_ctl)
2463*4882a593Smuzhiyun {
2464*4882a593Smuzhiyun struct snd_card *card;
2465*4882a593Smuzhiyun struct snd_kcontrol_new snd_control;
2466*4882a593Smuzhiyun
2467*4882a593Smuzhiyun struct clk_cache *clkcache;
2468*4882a593Smuzhiyun u32 hSC = hpi_ctl->h_control;
2469*4882a593Smuzhiyun int has_aes_in = 0;
2470*4882a593Smuzhiyun int i, j;
2471*4882a593Smuzhiyun u16 source;
2472*4882a593Smuzhiyun
2473*4882a593Smuzhiyun if (snd_BUG_ON(!asihpi))
2474*4882a593Smuzhiyun return -EINVAL;
2475*4882a593Smuzhiyun card = asihpi->card;
2476*4882a593Smuzhiyun clkcache = &asihpi->cc;
2477*4882a593Smuzhiyun snd_control.private_value = hpi_ctl->h_control;
2478*4882a593Smuzhiyun
2479*4882a593Smuzhiyun clkcache->has_local = 0;
2480*4882a593Smuzhiyun
2481*4882a593Smuzhiyun for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) {
2482*4882a593Smuzhiyun if (hpi_sample_clock_query_source(hSC,
2483*4882a593Smuzhiyun i, &source))
2484*4882a593Smuzhiyun break;
2485*4882a593Smuzhiyun clkcache->s[i].source = source;
2486*4882a593Smuzhiyun clkcache->s[i].index = 0;
2487*4882a593Smuzhiyun clkcache->s[i].name = sampleclock_sources[source];
2488*4882a593Smuzhiyun if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
2489*4882a593Smuzhiyun has_aes_in = 1;
2490*4882a593Smuzhiyun if (source == HPI_SAMPLECLOCK_SOURCE_LOCAL)
2491*4882a593Smuzhiyun clkcache->has_local = 1;
2492*4882a593Smuzhiyun }
2493*4882a593Smuzhiyun if (has_aes_in)
2494*4882a593Smuzhiyun /* already will have picked up index 0 above */
2495*4882a593Smuzhiyun for (j = 1; j < 8; j++) {
2496*4882a593Smuzhiyun if (hpi_sample_clock_query_source_index(hSC,
2497*4882a593Smuzhiyun j, HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT,
2498*4882a593Smuzhiyun &source))
2499*4882a593Smuzhiyun break;
2500*4882a593Smuzhiyun clkcache->s[i].source =
2501*4882a593Smuzhiyun HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT;
2502*4882a593Smuzhiyun clkcache->s[i].index = j;
2503*4882a593Smuzhiyun clkcache->s[i].name = sampleclock_sources[
2504*4882a593Smuzhiyun j+HPI_SAMPLECLOCK_SOURCE_LAST];
2505*4882a593Smuzhiyun i++;
2506*4882a593Smuzhiyun }
2507*4882a593Smuzhiyun clkcache->count = i;
2508*4882a593Smuzhiyun
2509*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Source");
2510*4882a593Smuzhiyun snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2511*4882a593Smuzhiyun snd_control.info = snd_asihpi_clksrc_info;
2512*4882a593Smuzhiyun snd_control.get = snd_asihpi_clksrc_get;
2513*4882a593Smuzhiyun snd_control.put = snd_asihpi_clksrc_put;
2514*4882a593Smuzhiyun if (ctl_add(card, &snd_control, asihpi) < 0)
2515*4882a593Smuzhiyun return -EINVAL;
2516*4882a593Smuzhiyun
2517*4882a593Smuzhiyun
2518*4882a593Smuzhiyun if (clkcache->has_local) {
2519*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Localrate");
2520*4882a593Smuzhiyun snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
2521*4882a593Smuzhiyun snd_control.info = snd_asihpi_clklocal_info;
2522*4882a593Smuzhiyun snd_control.get = snd_asihpi_clklocal_get;
2523*4882a593Smuzhiyun snd_control.put = snd_asihpi_clklocal_put;
2524*4882a593Smuzhiyun
2525*4882a593Smuzhiyun
2526*4882a593Smuzhiyun if (ctl_add(card, &snd_control, asihpi) < 0)
2527*4882a593Smuzhiyun return -EINVAL;
2528*4882a593Smuzhiyun }
2529*4882a593Smuzhiyun
2530*4882a593Smuzhiyun asihpi_ctl_init(&snd_control, hpi_ctl, "Rate");
2531*4882a593Smuzhiyun snd_control.access =
2532*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
2533*4882a593Smuzhiyun snd_control.info = snd_asihpi_clkrate_info;
2534*4882a593Smuzhiyun snd_control.get = snd_asihpi_clkrate_get;
2535*4882a593Smuzhiyun
2536*4882a593Smuzhiyun return ctl_add(card, &snd_control, asihpi);
2537*4882a593Smuzhiyun }
2538*4882a593Smuzhiyun /*------------------------------------------------------------
2539*4882a593Smuzhiyun Mixer
2540*4882a593Smuzhiyun ------------------------------------------------------------*/
2541*4882a593Smuzhiyun
snd_card_asihpi_mixer_new(struct snd_card_asihpi * asihpi)2542*4882a593Smuzhiyun static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
2543*4882a593Smuzhiyun {
2544*4882a593Smuzhiyun struct snd_card *card;
2545*4882a593Smuzhiyun unsigned int idx = 0;
2546*4882a593Smuzhiyun unsigned int subindex = 0;
2547*4882a593Smuzhiyun int err;
2548*4882a593Smuzhiyun struct hpi_control hpi_ctl, prev_ctl;
2549*4882a593Smuzhiyun
2550*4882a593Smuzhiyun if (snd_BUG_ON(!asihpi))
2551*4882a593Smuzhiyun return -EINVAL;
2552*4882a593Smuzhiyun card = asihpi->card;
2553*4882a593Smuzhiyun strcpy(card->mixername, "Asihpi Mixer");
2554*4882a593Smuzhiyun
2555*4882a593Smuzhiyun err =
2556*4882a593Smuzhiyun hpi_mixer_open(asihpi->hpi->adapter->index,
2557*4882a593Smuzhiyun &asihpi->h_mixer);
2558*4882a593Smuzhiyun hpi_handle_error(err);
2559*4882a593Smuzhiyun if (err)
2560*4882a593Smuzhiyun return -err;
2561*4882a593Smuzhiyun
2562*4882a593Smuzhiyun memset(&prev_ctl, 0, sizeof(prev_ctl));
2563*4882a593Smuzhiyun prev_ctl.control_type = -1;
2564*4882a593Smuzhiyun
2565*4882a593Smuzhiyun for (idx = 0; idx < 2000; idx++) {
2566*4882a593Smuzhiyun err = hpi_mixer_get_control_by_index(
2567*4882a593Smuzhiyun asihpi->h_mixer,
2568*4882a593Smuzhiyun idx,
2569*4882a593Smuzhiyun &hpi_ctl.src_node_type,
2570*4882a593Smuzhiyun &hpi_ctl.src_node_index,
2571*4882a593Smuzhiyun &hpi_ctl.dst_node_type,
2572*4882a593Smuzhiyun &hpi_ctl.dst_node_index,
2573*4882a593Smuzhiyun &hpi_ctl.control_type,
2574*4882a593Smuzhiyun &hpi_ctl.h_control);
2575*4882a593Smuzhiyun if (err) {
2576*4882a593Smuzhiyun if (err == HPI_ERROR_CONTROL_DISABLED) {
2577*4882a593Smuzhiyun if (mixer_dump)
2578*4882a593Smuzhiyun dev_info(&asihpi->pci->dev,
2579*4882a593Smuzhiyun "Disabled HPI Control(%d)\n",
2580*4882a593Smuzhiyun idx);
2581*4882a593Smuzhiyun continue;
2582*4882a593Smuzhiyun } else
2583*4882a593Smuzhiyun break;
2584*4882a593Smuzhiyun
2585*4882a593Smuzhiyun }
2586*4882a593Smuzhiyun
2587*4882a593Smuzhiyun hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE;
2588*4882a593Smuzhiyun hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE;
2589*4882a593Smuzhiyun
2590*4882a593Smuzhiyun /* ASI50xx in SSX mode has multiple meters on the same node.
2591*4882a593Smuzhiyun Use subindex to create distinct ALSA controls
2592*4882a593Smuzhiyun for any duplicated controls.
2593*4882a593Smuzhiyun */
2594*4882a593Smuzhiyun if ((hpi_ctl.control_type == prev_ctl.control_type) &&
2595*4882a593Smuzhiyun (hpi_ctl.src_node_type == prev_ctl.src_node_type) &&
2596*4882a593Smuzhiyun (hpi_ctl.src_node_index == prev_ctl.src_node_index) &&
2597*4882a593Smuzhiyun (hpi_ctl.dst_node_type == prev_ctl.dst_node_type) &&
2598*4882a593Smuzhiyun (hpi_ctl.dst_node_index == prev_ctl.dst_node_index))
2599*4882a593Smuzhiyun subindex++;
2600*4882a593Smuzhiyun else
2601*4882a593Smuzhiyun subindex = 0;
2602*4882a593Smuzhiyun
2603*4882a593Smuzhiyun prev_ctl = hpi_ctl;
2604*4882a593Smuzhiyun
2605*4882a593Smuzhiyun switch (hpi_ctl.control_type) {
2606*4882a593Smuzhiyun case HPI_CONTROL_VOLUME:
2607*4882a593Smuzhiyun err = snd_asihpi_volume_add(asihpi, &hpi_ctl);
2608*4882a593Smuzhiyun break;
2609*4882a593Smuzhiyun case HPI_CONTROL_LEVEL:
2610*4882a593Smuzhiyun err = snd_asihpi_level_add(asihpi, &hpi_ctl);
2611*4882a593Smuzhiyun break;
2612*4882a593Smuzhiyun case HPI_CONTROL_MULTIPLEXER:
2613*4882a593Smuzhiyun err = snd_asihpi_mux_add(asihpi, &hpi_ctl);
2614*4882a593Smuzhiyun break;
2615*4882a593Smuzhiyun case HPI_CONTROL_CHANNEL_MODE:
2616*4882a593Smuzhiyun err = snd_asihpi_cmode_add(asihpi, &hpi_ctl);
2617*4882a593Smuzhiyun break;
2618*4882a593Smuzhiyun case HPI_CONTROL_METER:
2619*4882a593Smuzhiyun err = snd_asihpi_meter_add(asihpi, &hpi_ctl, subindex);
2620*4882a593Smuzhiyun break;
2621*4882a593Smuzhiyun case HPI_CONTROL_SAMPLECLOCK:
2622*4882a593Smuzhiyun err = snd_asihpi_sampleclock_add(
2623*4882a593Smuzhiyun asihpi, &hpi_ctl);
2624*4882a593Smuzhiyun break;
2625*4882a593Smuzhiyun case HPI_CONTROL_CONNECTION: /* ignore these */
2626*4882a593Smuzhiyun continue;
2627*4882a593Smuzhiyun case HPI_CONTROL_TUNER:
2628*4882a593Smuzhiyun err = snd_asihpi_tuner_add(asihpi, &hpi_ctl);
2629*4882a593Smuzhiyun break;
2630*4882a593Smuzhiyun case HPI_CONTROL_AESEBU_TRANSMITTER:
2631*4882a593Smuzhiyun err = snd_asihpi_aesebu_tx_add(asihpi, &hpi_ctl);
2632*4882a593Smuzhiyun break;
2633*4882a593Smuzhiyun case HPI_CONTROL_AESEBU_RECEIVER:
2634*4882a593Smuzhiyun err = snd_asihpi_aesebu_rx_add(asihpi, &hpi_ctl);
2635*4882a593Smuzhiyun break;
2636*4882a593Smuzhiyun case HPI_CONTROL_VOX:
2637*4882a593Smuzhiyun case HPI_CONTROL_BITSTREAM:
2638*4882a593Smuzhiyun case HPI_CONTROL_MICROPHONE:
2639*4882a593Smuzhiyun case HPI_CONTROL_PARAMETRIC_EQ:
2640*4882a593Smuzhiyun case HPI_CONTROL_COMPANDER:
2641*4882a593Smuzhiyun default:
2642*4882a593Smuzhiyun if (mixer_dump)
2643*4882a593Smuzhiyun dev_info(&asihpi->pci->dev,
2644*4882a593Smuzhiyun "Untranslated HPI Control (%d) %d %d %d %d %d\n",
2645*4882a593Smuzhiyun idx,
2646*4882a593Smuzhiyun hpi_ctl.control_type,
2647*4882a593Smuzhiyun hpi_ctl.src_node_type,
2648*4882a593Smuzhiyun hpi_ctl.src_node_index,
2649*4882a593Smuzhiyun hpi_ctl.dst_node_type,
2650*4882a593Smuzhiyun hpi_ctl.dst_node_index);
2651*4882a593Smuzhiyun continue;
2652*4882a593Smuzhiyun }
2653*4882a593Smuzhiyun if (err < 0)
2654*4882a593Smuzhiyun return err;
2655*4882a593Smuzhiyun }
2656*4882a593Smuzhiyun if (HPI_ERROR_INVALID_OBJ_INDEX != err)
2657*4882a593Smuzhiyun hpi_handle_error(err);
2658*4882a593Smuzhiyun
2659*4882a593Smuzhiyun dev_info(&asihpi->pci->dev, "%d mixer controls found\n", idx);
2660*4882a593Smuzhiyun
2661*4882a593Smuzhiyun return 0;
2662*4882a593Smuzhiyun }
2663*4882a593Smuzhiyun
2664*4882a593Smuzhiyun /*------------------------------------------------------------
2665*4882a593Smuzhiyun /proc interface
2666*4882a593Smuzhiyun ------------------------------------------------------------*/
2667*4882a593Smuzhiyun
2668*4882a593Smuzhiyun static void
snd_asihpi_proc_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)2669*4882a593Smuzhiyun snd_asihpi_proc_read(struct snd_info_entry *entry,
2670*4882a593Smuzhiyun struct snd_info_buffer *buffer)
2671*4882a593Smuzhiyun {
2672*4882a593Smuzhiyun struct snd_card_asihpi *asihpi = entry->private_data;
2673*4882a593Smuzhiyun u32 h_control;
2674*4882a593Smuzhiyun u32 rate = 0;
2675*4882a593Smuzhiyun u16 source = 0;
2676*4882a593Smuzhiyun
2677*4882a593Smuzhiyun u16 num_outstreams;
2678*4882a593Smuzhiyun u16 num_instreams;
2679*4882a593Smuzhiyun u16 version;
2680*4882a593Smuzhiyun u32 serial_number;
2681*4882a593Smuzhiyun u16 type;
2682*4882a593Smuzhiyun
2683*4882a593Smuzhiyun int err;
2684*4882a593Smuzhiyun
2685*4882a593Smuzhiyun snd_iprintf(buffer, "ASIHPI driver proc file\n");
2686*4882a593Smuzhiyun
2687*4882a593Smuzhiyun hpi_handle_error(hpi_adapter_get_info(asihpi->hpi->adapter->index,
2688*4882a593Smuzhiyun &num_outstreams, &num_instreams,
2689*4882a593Smuzhiyun &version, &serial_number, &type));
2690*4882a593Smuzhiyun
2691*4882a593Smuzhiyun snd_iprintf(buffer,
2692*4882a593Smuzhiyun "Adapter type ASI%4X\nHardware Index %d\n"
2693*4882a593Smuzhiyun "%d outstreams\n%d instreams\n",
2694*4882a593Smuzhiyun type, asihpi->hpi->adapter->index,
2695*4882a593Smuzhiyun num_outstreams, num_instreams);
2696*4882a593Smuzhiyun
2697*4882a593Smuzhiyun snd_iprintf(buffer,
2698*4882a593Smuzhiyun "Serial#%d\nHardware version %c%d\nDSP code version %03d\n",
2699*4882a593Smuzhiyun serial_number, ((version >> 3) & 0xf) + 'A', version & 0x7,
2700*4882a593Smuzhiyun ((version >> 13) * 100) + ((version >> 7) & 0x3f));
2701*4882a593Smuzhiyun
2702*4882a593Smuzhiyun err = hpi_mixer_get_control(asihpi->h_mixer,
2703*4882a593Smuzhiyun HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2704*4882a593Smuzhiyun HPI_CONTROL_SAMPLECLOCK, &h_control);
2705*4882a593Smuzhiyun
2706*4882a593Smuzhiyun if (!err) {
2707*4882a593Smuzhiyun err = hpi_sample_clock_get_sample_rate(h_control, &rate);
2708*4882a593Smuzhiyun err += hpi_sample_clock_get_source(h_control, &source);
2709*4882a593Smuzhiyun
2710*4882a593Smuzhiyun if (!err)
2711*4882a593Smuzhiyun snd_iprintf(buffer, "Sample Clock %dHz, source %s\n",
2712*4882a593Smuzhiyun rate, sampleclock_sources[source]);
2713*4882a593Smuzhiyun }
2714*4882a593Smuzhiyun }
2715*4882a593Smuzhiyun
snd_asihpi_proc_init(struct snd_card_asihpi * asihpi)2716*4882a593Smuzhiyun static void snd_asihpi_proc_init(struct snd_card_asihpi *asihpi)
2717*4882a593Smuzhiyun {
2718*4882a593Smuzhiyun snd_card_ro_proc_new(asihpi->card, "info", asihpi,
2719*4882a593Smuzhiyun snd_asihpi_proc_read);
2720*4882a593Smuzhiyun }
2721*4882a593Smuzhiyun
2722*4882a593Smuzhiyun /*------------------------------------------------------------
2723*4882a593Smuzhiyun HWDEP
2724*4882a593Smuzhiyun ------------------------------------------------------------*/
2725*4882a593Smuzhiyun
snd_asihpi_hpi_open(struct snd_hwdep * hw,struct file * file)2726*4882a593Smuzhiyun static int snd_asihpi_hpi_open(struct snd_hwdep *hw, struct file *file)
2727*4882a593Smuzhiyun {
2728*4882a593Smuzhiyun if (enable_hpi_hwdep)
2729*4882a593Smuzhiyun return 0;
2730*4882a593Smuzhiyun else
2731*4882a593Smuzhiyun return -ENODEV;
2732*4882a593Smuzhiyun
2733*4882a593Smuzhiyun }
2734*4882a593Smuzhiyun
snd_asihpi_hpi_release(struct snd_hwdep * hw,struct file * file)2735*4882a593Smuzhiyun static int snd_asihpi_hpi_release(struct snd_hwdep *hw, struct file *file)
2736*4882a593Smuzhiyun {
2737*4882a593Smuzhiyun if (enable_hpi_hwdep)
2738*4882a593Smuzhiyun return asihpi_hpi_release(file);
2739*4882a593Smuzhiyun else
2740*4882a593Smuzhiyun return -ENODEV;
2741*4882a593Smuzhiyun }
2742*4882a593Smuzhiyun
snd_asihpi_hpi_ioctl(struct snd_hwdep * hw,struct file * file,unsigned int cmd,unsigned long arg)2743*4882a593Smuzhiyun static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file,
2744*4882a593Smuzhiyun unsigned int cmd, unsigned long arg)
2745*4882a593Smuzhiyun {
2746*4882a593Smuzhiyun if (enable_hpi_hwdep)
2747*4882a593Smuzhiyun return asihpi_hpi_ioctl(file, cmd, arg);
2748*4882a593Smuzhiyun else
2749*4882a593Smuzhiyun return -ENODEV;
2750*4882a593Smuzhiyun }
2751*4882a593Smuzhiyun
2752*4882a593Smuzhiyun
2753*4882a593Smuzhiyun /* results in /dev/snd/hwC#D0 file for each card with index #
2754*4882a593Smuzhiyun also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'
2755*4882a593Smuzhiyun */
snd_asihpi_hpi_new(struct snd_card_asihpi * asihpi,int device)2756*4882a593Smuzhiyun static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device)
2757*4882a593Smuzhiyun {
2758*4882a593Smuzhiyun struct snd_hwdep *hw;
2759*4882a593Smuzhiyun int err;
2760*4882a593Smuzhiyun
2761*4882a593Smuzhiyun err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
2762*4882a593Smuzhiyun if (err < 0)
2763*4882a593Smuzhiyun return err;
2764*4882a593Smuzhiyun strcpy(hw->name, "asihpi (HPI)");
2765*4882a593Smuzhiyun hw->iface = SNDRV_HWDEP_IFACE_LAST;
2766*4882a593Smuzhiyun hw->ops.open = snd_asihpi_hpi_open;
2767*4882a593Smuzhiyun hw->ops.ioctl = snd_asihpi_hpi_ioctl;
2768*4882a593Smuzhiyun hw->ops.release = snd_asihpi_hpi_release;
2769*4882a593Smuzhiyun hw->private_data = asihpi;
2770*4882a593Smuzhiyun return 0;
2771*4882a593Smuzhiyun }
2772*4882a593Smuzhiyun
2773*4882a593Smuzhiyun /*------------------------------------------------------------
2774*4882a593Smuzhiyun CARD
2775*4882a593Smuzhiyun ------------------------------------------------------------*/
snd_asihpi_probe(struct pci_dev * pci_dev,const struct pci_device_id * pci_id)2776*4882a593Smuzhiyun static int snd_asihpi_probe(struct pci_dev *pci_dev,
2777*4882a593Smuzhiyun const struct pci_device_id *pci_id)
2778*4882a593Smuzhiyun {
2779*4882a593Smuzhiyun int err;
2780*4882a593Smuzhiyun struct hpi_adapter *hpi;
2781*4882a593Smuzhiyun struct snd_card *card;
2782*4882a593Smuzhiyun struct snd_card_asihpi *asihpi;
2783*4882a593Smuzhiyun
2784*4882a593Smuzhiyun u32 h_control;
2785*4882a593Smuzhiyun u32 h_stream;
2786*4882a593Smuzhiyun u32 adapter_index;
2787*4882a593Smuzhiyun
2788*4882a593Smuzhiyun static int dev;
2789*4882a593Smuzhiyun if (dev >= SNDRV_CARDS)
2790*4882a593Smuzhiyun return -ENODEV;
2791*4882a593Smuzhiyun
2792*4882a593Smuzhiyun /* Should this be enable[hpi->index] ? */
2793*4882a593Smuzhiyun if (!enable[dev]) {
2794*4882a593Smuzhiyun dev++;
2795*4882a593Smuzhiyun return -ENOENT;
2796*4882a593Smuzhiyun }
2797*4882a593Smuzhiyun
2798*4882a593Smuzhiyun /* Initialise low-level HPI driver */
2799*4882a593Smuzhiyun err = asihpi_adapter_probe(pci_dev, pci_id);
2800*4882a593Smuzhiyun if (err < 0)
2801*4882a593Smuzhiyun return err;
2802*4882a593Smuzhiyun
2803*4882a593Smuzhiyun hpi = pci_get_drvdata(pci_dev);
2804*4882a593Smuzhiyun adapter_index = hpi->adapter->index;
2805*4882a593Smuzhiyun /* first try to give the card the same index as its hardware index */
2806*4882a593Smuzhiyun err = snd_card_new(&pci_dev->dev, adapter_index, id[adapter_index],
2807*4882a593Smuzhiyun THIS_MODULE, sizeof(struct snd_card_asihpi), &card);
2808*4882a593Smuzhiyun if (err < 0) {
2809*4882a593Smuzhiyun /* if that fails, try the default index==next available */
2810*4882a593Smuzhiyun err = snd_card_new(&pci_dev->dev, index[dev], id[dev],
2811*4882a593Smuzhiyun THIS_MODULE, sizeof(struct snd_card_asihpi),
2812*4882a593Smuzhiyun &card);
2813*4882a593Smuzhiyun if (err < 0)
2814*4882a593Smuzhiyun return err;
2815*4882a593Smuzhiyun dev_warn(&pci_dev->dev, "Adapter index %d->ALSA index %d\n",
2816*4882a593Smuzhiyun adapter_index, card->number);
2817*4882a593Smuzhiyun }
2818*4882a593Smuzhiyun
2819*4882a593Smuzhiyun asihpi = card->private_data;
2820*4882a593Smuzhiyun asihpi->card = card;
2821*4882a593Smuzhiyun asihpi->pci = pci_dev;
2822*4882a593Smuzhiyun asihpi->hpi = hpi;
2823*4882a593Smuzhiyun hpi->snd_card = card;
2824*4882a593Smuzhiyun
2825*4882a593Smuzhiyun err = hpi_adapter_get_property(adapter_index,
2826*4882a593Smuzhiyun HPI_ADAPTER_PROPERTY_CAPS1,
2827*4882a593Smuzhiyun NULL, &asihpi->support_grouping);
2828*4882a593Smuzhiyun if (err)
2829*4882a593Smuzhiyun asihpi->support_grouping = 0;
2830*4882a593Smuzhiyun
2831*4882a593Smuzhiyun err = hpi_adapter_get_property(adapter_index,
2832*4882a593Smuzhiyun HPI_ADAPTER_PROPERTY_CAPS2,
2833*4882a593Smuzhiyun &asihpi->support_mrx, NULL);
2834*4882a593Smuzhiyun if (err)
2835*4882a593Smuzhiyun asihpi->support_mrx = 0;
2836*4882a593Smuzhiyun
2837*4882a593Smuzhiyun err = hpi_adapter_get_property(adapter_index,
2838*4882a593Smuzhiyun HPI_ADAPTER_PROPERTY_INTERVAL,
2839*4882a593Smuzhiyun NULL, &asihpi->update_interval_frames);
2840*4882a593Smuzhiyun if (err)
2841*4882a593Smuzhiyun asihpi->update_interval_frames = 512;
2842*4882a593Smuzhiyun
2843*4882a593Smuzhiyun if (hpi->interrupt_mode) {
2844*4882a593Smuzhiyun asihpi->pcm_start = snd_card_asihpi_pcm_int_start;
2845*4882a593Smuzhiyun asihpi->pcm_stop = snd_card_asihpi_pcm_int_stop;
2846*4882a593Smuzhiyun hpi->interrupt_callback = snd_card_asihpi_isr;
2847*4882a593Smuzhiyun } else {
2848*4882a593Smuzhiyun asihpi->pcm_start = snd_card_asihpi_pcm_timer_start;
2849*4882a593Smuzhiyun asihpi->pcm_stop = snd_card_asihpi_pcm_timer_stop;
2850*4882a593Smuzhiyun }
2851*4882a593Smuzhiyun
2852*4882a593Smuzhiyun hpi_handle_error(hpi_instream_open(adapter_index,
2853*4882a593Smuzhiyun 0, &h_stream));
2854*4882a593Smuzhiyun
2855*4882a593Smuzhiyun err = hpi_instream_host_buffer_free(h_stream);
2856*4882a593Smuzhiyun asihpi->can_dma = (!err);
2857*4882a593Smuzhiyun
2858*4882a593Smuzhiyun hpi_handle_error(hpi_instream_close(h_stream));
2859*4882a593Smuzhiyun
2860*4882a593Smuzhiyun if (!asihpi->can_dma)
2861*4882a593Smuzhiyun asihpi->update_interval_frames *= 2;
2862*4882a593Smuzhiyun
2863*4882a593Smuzhiyun err = hpi_adapter_get_property(adapter_index,
2864*4882a593Smuzhiyun HPI_ADAPTER_PROPERTY_CURCHANNELS,
2865*4882a593Smuzhiyun &asihpi->in_max_chans, &asihpi->out_max_chans);
2866*4882a593Smuzhiyun if (err) {
2867*4882a593Smuzhiyun asihpi->in_max_chans = 2;
2868*4882a593Smuzhiyun asihpi->out_max_chans = 2;
2869*4882a593Smuzhiyun }
2870*4882a593Smuzhiyun
2871*4882a593Smuzhiyun if (asihpi->out_max_chans > 2) { /* assume LL mode */
2872*4882a593Smuzhiyun asihpi->out_min_chans = asihpi->out_max_chans;
2873*4882a593Smuzhiyun asihpi->in_min_chans = asihpi->in_max_chans;
2874*4882a593Smuzhiyun asihpi->support_grouping = 0;
2875*4882a593Smuzhiyun } else {
2876*4882a593Smuzhiyun asihpi->out_min_chans = 1;
2877*4882a593Smuzhiyun asihpi->in_min_chans = 1;
2878*4882a593Smuzhiyun }
2879*4882a593Smuzhiyun
2880*4882a593Smuzhiyun dev_info(&pci_dev->dev, "Has dma:%d, grouping:%d, mrx:%d, uif:%d\n",
2881*4882a593Smuzhiyun asihpi->can_dma,
2882*4882a593Smuzhiyun asihpi->support_grouping,
2883*4882a593Smuzhiyun asihpi->support_mrx,
2884*4882a593Smuzhiyun asihpi->update_interval_frames
2885*4882a593Smuzhiyun );
2886*4882a593Smuzhiyun
2887*4882a593Smuzhiyun err = snd_card_asihpi_pcm_new(asihpi, 0);
2888*4882a593Smuzhiyun if (err < 0) {
2889*4882a593Smuzhiyun dev_err(&pci_dev->dev, "pcm_new failed\n");
2890*4882a593Smuzhiyun goto __nodev;
2891*4882a593Smuzhiyun }
2892*4882a593Smuzhiyun err = snd_card_asihpi_mixer_new(asihpi);
2893*4882a593Smuzhiyun if (err < 0) {
2894*4882a593Smuzhiyun dev_err(&pci_dev->dev, "mixer_new failed\n");
2895*4882a593Smuzhiyun goto __nodev;
2896*4882a593Smuzhiyun }
2897*4882a593Smuzhiyun
2898*4882a593Smuzhiyun err = hpi_mixer_get_control(asihpi->h_mixer,
2899*4882a593Smuzhiyun HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
2900*4882a593Smuzhiyun HPI_CONTROL_SAMPLECLOCK, &h_control);
2901*4882a593Smuzhiyun
2902*4882a593Smuzhiyun if (!err)
2903*4882a593Smuzhiyun err = hpi_sample_clock_set_local_rate(
2904*4882a593Smuzhiyun h_control, adapter_fs);
2905*4882a593Smuzhiyun
2906*4882a593Smuzhiyun snd_asihpi_proc_init(asihpi);
2907*4882a593Smuzhiyun
2908*4882a593Smuzhiyun /* always create, can be enabled or disabled dynamically
2909*4882a593Smuzhiyun by enable_hwdep module param*/
2910*4882a593Smuzhiyun snd_asihpi_hpi_new(asihpi, 0);
2911*4882a593Smuzhiyun
2912*4882a593Smuzhiyun strcpy(card->driver, "ASIHPI");
2913*4882a593Smuzhiyun
2914*4882a593Smuzhiyun sprintf(card->shortname, "AudioScience ASI%4X",
2915*4882a593Smuzhiyun asihpi->hpi->adapter->type);
2916*4882a593Smuzhiyun sprintf(card->longname, "%s %i",
2917*4882a593Smuzhiyun card->shortname, adapter_index);
2918*4882a593Smuzhiyun err = snd_card_register(card);
2919*4882a593Smuzhiyun
2920*4882a593Smuzhiyun if (!err) {
2921*4882a593Smuzhiyun dev++;
2922*4882a593Smuzhiyun return 0;
2923*4882a593Smuzhiyun }
2924*4882a593Smuzhiyun __nodev:
2925*4882a593Smuzhiyun snd_card_free(card);
2926*4882a593Smuzhiyun dev_err(&pci_dev->dev, "snd_asihpi_probe error %d\n", err);
2927*4882a593Smuzhiyun return err;
2928*4882a593Smuzhiyun
2929*4882a593Smuzhiyun }
2930*4882a593Smuzhiyun
snd_asihpi_remove(struct pci_dev * pci_dev)2931*4882a593Smuzhiyun static void snd_asihpi_remove(struct pci_dev *pci_dev)
2932*4882a593Smuzhiyun {
2933*4882a593Smuzhiyun struct hpi_adapter *hpi = pci_get_drvdata(pci_dev);
2934*4882a593Smuzhiyun
2935*4882a593Smuzhiyun /* Stop interrupts */
2936*4882a593Smuzhiyun if (hpi->interrupt_mode) {
2937*4882a593Smuzhiyun hpi->interrupt_callback = NULL;
2938*4882a593Smuzhiyun hpi_handle_error(hpi_adapter_set_property(hpi->adapter->index,
2939*4882a593Smuzhiyun HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0));
2940*4882a593Smuzhiyun }
2941*4882a593Smuzhiyun
2942*4882a593Smuzhiyun snd_card_free(hpi->snd_card);
2943*4882a593Smuzhiyun hpi->snd_card = NULL;
2944*4882a593Smuzhiyun asihpi_adapter_remove(pci_dev);
2945*4882a593Smuzhiyun }
2946*4882a593Smuzhiyun
2947*4882a593Smuzhiyun static const struct pci_device_id asihpi_pci_tbl[] = {
2948*4882a593Smuzhiyun {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
2949*4882a593Smuzhiyun HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2950*4882a593Smuzhiyun (kernel_ulong_t)HPI_6205},
2951*4882a593Smuzhiyun {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
2952*4882a593Smuzhiyun HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
2953*4882a593Smuzhiyun (kernel_ulong_t)HPI_6000},
2954*4882a593Smuzhiyun {0,}
2955*4882a593Smuzhiyun };
2956*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);
2957*4882a593Smuzhiyun
2958*4882a593Smuzhiyun static struct pci_driver driver = {
2959*4882a593Smuzhiyun .name = KBUILD_MODNAME,
2960*4882a593Smuzhiyun .id_table = asihpi_pci_tbl,
2961*4882a593Smuzhiyun .probe = snd_asihpi_probe,
2962*4882a593Smuzhiyun .remove = snd_asihpi_remove,
2963*4882a593Smuzhiyun };
2964*4882a593Smuzhiyun
snd_asihpi_init(void)2965*4882a593Smuzhiyun static int __init snd_asihpi_init(void)
2966*4882a593Smuzhiyun {
2967*4882a593Smuzhiyun asihpi_init();
2968*4882a593Smuzhiyun return pci_register_driver(&driver);
2969*4882a593Smuzhiyun }
2970*4882a593Smuzhiyun
snd_asihpi_exit(void)2971*4882a593Smuzhiyun static void __exit snd_asihpi_exit(void)
2972*4882a593Smuzhiyun {
2973*4882a593Smuzhiyun
2974*4882a593Smuzhiyun pci_unregister_driver(&driver);
2975*4882a593Smuzhiyun asihpi_exit();
2976*4882a593Smuzhiyun }
2977*4882a593Smuzhiyun
2978*4882a593Smuzhiyun module_init(snd_asihpi_init)
2979*4882a593Smuzhiyun module_exit(snd_asihpi_exit)
2980*4882a593Smuzhiyun
2981