~ubuntu-branches/ubuntu/oneiric/oss4/oneiric-proposed

« back to all changes in this revision

Viewing changes to kernel/drv/oss_hdaudio/hdaudio_si3055.c

  • Committer: Bazaar Package Importer
  • Author(s): Stefano Rivera
  • Date: 2011-06-16 20:37:48 UTC
  • mfrom: (5.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110616203748-jbrxik6ql33z54co
Tags: 4.2-build2004-1ubuntu1
* Merge from Debian unstable.
  - Supports our current kernel (LP: #746048)
  Remaining changes:
  - debian/oss4-dkms.dkms.in: s/source/build/ in Kernel headers paths.
* ld-as-needed.patch: Re-order CC arguments to enable building with ld
  --as-needed (LP: #770972)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Purpose: Driver for Si3055 and compatible modems.
 
3
 */
 
4
/*
 
5
 *
 
6
 * This file is part of Open Sound System.
 
7
 *
 
8
 * Copyright (C) 4Front Technologies 1996-2008.
 
9
 *
 
10
 * This this source file is released under GPL v2 license (no other versions).
 
11
 * See the COPYING file included in the main directory of this source
 
12
 * distribution for the license terms and conditions.
 
13
 *
 
14
 */
 
15
 
 
16
 
 
17
/*
 
18
 * Documentation Note
 
19
 * 
 
20
 * There is no publicly available documentation for Si3055. However,
 
21
 * there is a very similar modem (Si3038) for which a datasheet is
 
22
 * publicly available:
 
23
 * 
 
24
 * https://www.silabs.com/Support%20Documents/TechnicalDocs/si3038.pdf
 
25
 * 
 
26
 * This driver was written by reading the ALSA code, looking for a
 
27
 * similar modem (Si3038), and figuring out the corresponding Si3055
 
28
 * register IDs for Si3038 registers, again by reading the ALSA code,
 
29
 * and by checking the default after-reset values.
 
30
 * 
 
31
 */
 
32
 
 
33
#include "oss_hdaudio_cfg.h"
 
34
#include "hdaudio.h"
 
35
#include "hdaudio_codec.h"
 
36
#include "hdaudio_dedicated.h"
 
37
#include "hdaudio_mixers.h"
 
38
 
 
39
/*
 
40
 * Si3055 register IDs.
 
41
 */
 
42
#define SI3055_EXT_MODEM_STATUS 2
 
43
#define SI3055_LINE_RATE  3
 
44
#define SI3055_HDA_STREAMS      4
 
45
#define SI3055_GPIO_CONFIG      5
 
46
#define SI3055_GPIO_PIN_STATUS  10
 
47
#define SI3055_LINE_CONFIG      13
 
48
 
 
49
 
 
50
/* Corresponding registers in Si3038 (for reference):
 
51
 * 
 
52
 * SI3055_EXT_MODEM_STATUS      3Eh (Extended Modem Status & Control)
 
53
 * SI3055_LINE_RATE             40h (Line 1 DAC/ADC Rate)
 
54
 * SI3055_GPIO_PIN_STATUS       54h (GPIO Pin Status)
 
55
 * SI3055_LINE_CONFIG           56h (Line Side Configuration 1)
 
56
 */
 
57
 
 
58
/*
 
59
 * The SI3055_HDA_STREAMS register has no corresponding in Si3038.
 
60
 * It contains the playback and recording stream descriptors in the
 
61
 * following format:
 
62
 * 
 
63
 *    ((playback_stream_num << 4) << 8) | (recording_stream_num << 4)
 
64
 */
 
65
 
 
66
/* Si3055 verbs. */
 
67
#define SI3055_REG_GET_VERB     0x900
 
68
#define SI3055_REG_SET_VERB     0x100
 
69
 
 
70
/* Convenience macros for reading from and writing to Si3055 registers. */
 
71
#define SI3055_REG_GET(mixer, cad, reg, a, b) corb_read(mixer, cad, reg, 0, SI3055_REG_GET_VERB, 0, a, b)
 
72
#define SI3055_REG_SET(mixer, cad, reg, val)  corb_write(mixer, cad, reg, 0, SI3055_REG_SET_VERB, val)
 
73
 
 
74
 
 
75
void hdaudio_si3055_set_rate(hdaudio_mixer_t *mixer, int cad, int rate)
 
76
{
 
77
  SI3055_REG_SET(mixer, cad, SI3055_LINE_RATE, rate);
 
78
}
 
79
 
 
80
int hdaudio_si3055_set_offhook(hdaudio_mixer_t *mixer, int cad, int offhook)
 
81
{
 
82
  unsigned int a, b;
 
83
  SI3055_REG_GET(mixer, cad, SI3055_GPIO_PIN_STATUS, &a, &b);
 
84
 
 
85
  if (offhook)
 
86
    {
 
87
      a |= 0x1;    /* Set Off-Hook bit */
 
88
    }
 
89
  else
 
90
    {
 
91
      a &= ~0x1;   /* Unset Off-Hook bit */
 
92
    }
 
93
 
 
94
  SI3055_REG_SET(mixer, cad, SI3055_GPIO_PIN_STATUS, a);
 
95
  SI3055_REG_GET(mixer, cad, SI3055_GPIO_PIN_STATUS, &a, &b);
 
96
  return ((a & 0x1) == 0x1);
 
97
}
 
98
 
 
99
void hdaudio_si3055_endpoint_init(hdaudio_mixer_t *mixer, int cad)
 
100
{
 
101
  codec_t *codec = mixer->codecs[cad];  /* Modem codec */
 
102
  widget_t *widget;                     /* MFG widget */
 
103
  hdaudio_endpointinfo_t *endpoint;
 
104
  unsigned int a, b;      /* Used for reading data. */
 
105
  int tmout;              /* Timeout counter. */
 
106
 
 
107
  /* Output and input stream numbers. */
 
108
  int playback_stream_num, recording_stream_num;
 
109
 
 
110
  
 
111
  DDB(cmn_err(CE_CONT, "hdaudio_si3055_endpoint_init got called.\n"));
 
112
 
 
113
  /* Reset the modem codec. */
 
114
  corb_write(mixer, cad, 0x00, 0, SET_CODEC_RESET, 0);
 
115
  corb_write(mixer, cad, codec->afg, 0, SET_CONVERTER, IDDLE_STREAM << 4);
 
116
  corb_write(mixer, cad, codec->afg, 0, SET_CONVERTER_FORMAT, 0);
 
117
  
 
118
  /* Set 9600Hz as the initial line sampling rate.
 
119
   * It can be changed later when desired.
 
120
   */
 
121
  SI3055_REG_SET(mixer, cad, SI3055_LINE_RATE, 9600);
 
122
  
 
123
  /* Assign the "unused" value to the playback and recording
 
124
   * stream descriptors (ref. HDAudio_03.pdf, page 40).
 
125
   */
 
126
  SI3055_REG_SET(mixer, cad, SI3055_HDA_STREAMS, 0x0000);
 
127
  
 
128
  /* Write 0x0000 to the Extended Modem Status & Control register
 
129
   * to power up the modem (ref. si3038.pdf, page 22).
 
130
   */
 
131
  SI3055_REG_SET(mixer, cad, SI3055_EXT_MODEM_STATUS, 0x0000);
 
132
  
 
133
  /* Wait for the modem to complete power up. The lower 8 bits
 
134
   * indicate that it is ready (ref. si3038.pdf, page 22).
 
135
   */
 
136
  tmout = 10;
 
137
  do
 
138
    {
 
139
      SI3055_REG_GET(mixer, cad, SI3055_EXT_MODEM_STATUS, &a, &b);
 
140
      DDB(cmn_err(CE_CONT, "si3055: ext modem status: %04x.\n", a));
 
141
      oss_udelay(1000);
 
142
    }
 
143
    while(((a & 0xf) == 0) && --tmout);
 
144
  
 
145
  if ((a & 0xf) == 0)
 
146
    {
 
147
      cmn_err(CE_WARN, "si3055: power up timeout (status: %04x).\n", a);
 
148
    }
 
149
  
 
150
  /* This register contains 0x1fff after reset. We need to set it
 
151
   * to zero to get the modem working. No corresponding register
 
152
   * could be found in the Si3038 datasheet.
 
153
   */
 
154
  SI3055_REG_SET(mixer, cad, SI3055_GPIO_CONFIG, 0x0000);
 
155
 
 
156
  /* Program line interface parameters. The register value after
 
157
   * a reset is 0xF010. Set it to 0x0010 to unmute the analog
 
158
   * receive and transmit paths.
 
159
   */
 
160
  SI3055_REG_SET(mixer, cad, SI3055_LINE_CONFIG, 0x0010);
 
161
      
 
162
  /* Setup the widget info. */
 
163
  widget = &codec->widgets[codec->afg];
 
164
  widget->endpoint = &codec->inendpoints[0];
 
165
  widget->sizes = 0x20000; /* 16 bits */
 
166
  strcpy(widget->name, "modem");
 
167
 
 
168
  /* Setup the output endpoint. */
 
169
  codec->num_outendpoints = 1;
 
170
  endpoint = &codec->outendpoints[0];
 
171
  endpoint->ix = 0;
 
172
  endpoint->iddle_stream = 0;
 
173
  endpoint->cad = cad;
 
174
  endpoint->base_wid = codec->afg;
 
175
  endpoint->recsrc_wid = endpoint->volume_wid = -1;
 
176
  endpoint->nrates = 3;
 
177
  endpoint->rates[0] = 8000;
 
178
  endpoint->rates[1] = 9600;
 
179
  endpoint->rates[2] = 16000;
 
180
  endpoint->name = widget->name;
 
181
  endpoint->channels = 1;
 
182
  endpoint->is_digital = 0;
 
183
  endpoint->is_modem = 1;
 
184
  endpoint->sizemask = widget->sizes;
 
185
  endpoint->fmt_mask = AFMT_S16_LE;
 
186
  endpoint->afg = codec->afg;
 
187
  endpoint->min_rate = 8000;
 
188
  endpoint->max_rate = 16000;
 
189
  
 
190
  /* Setup the input endpoint. */
 
191
  codec->num_inendpoints = 1;
 
192
  memcpy(&codec->inendpoints[0], endpoint, sizeof(*endpoint));
 
193
 
 
194
  /* Choose stream numbers for output and input streams. */
 
195
  playback_stream_num = ++mixer->num_outendpoints;
 
196
  endpoint->stream_number = endpoint->default_stream_number = playback_stream_num;
 
197
 
 
198
  endpoint = &codec->inendpoints[0];
 
199
  recording_stream_num = ++mixer->num_inendpoints;
 
200
  endpoint->stream_number = endpoint->default_stream_number = recording_stream_num;
 
201
 
 
202
  /* Setup the stream numbers. */
 
203
  SI3055_REG_SET(mixer, cad, SI3055_HDA_STREAMS, ((playback_stream_num  << 4) << 8) |
 
204
                                                  (recording_stream_num << 4));
 
205
}
 
206