2
* Purpose: Driver for Si3055 and compatible modems.
6
* This file is part of Open Sound System.
8
* Copyright (C) 4Front Technologies 1996-2008.
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.
20
* There is no publicly available documentation for Si3055. However,
21
* there is a very similar modem (Si3038) for which a datasheet is
24
* https://www.silabs.com/Support%20Documents/TechnicalDocs/si3038.pdf
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.
33
#include "oss_hdaudio_cfg.h"
35
#include "hdaudio_codec.h"
36
#include "hdaudio_dedicated.h"
37
#include "hdaudio_mixers.h"
40
* Si3055 register IDs.
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
50
/* Corresponding registers in Si3038 (for reference):
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)
59
* The SI3055_HDA_STREAMS register has no corresponding in Si3038.
60
* It contains the playback and recording stream descriptors in the
63
* ((playback_stream_num << 4) << 8) | (recording_stream_num << 4)
67
#define SI3055_REG_GET_VERB 0x900
68
#define SI3055_REG_SET_VERB 0x100
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)
75
void hdaudio_si3055_set_rate(hdaudio_mixer_t *mixer, int cad, int rate)
77
SI3055_REG_SET(mixer, cad, SI3055_LINE_RATE, rate);
80
int hdaudio_si3055_set_offhook(hdaudio_mixer_t *mixer, int cad, int offhook)
83
SI3055_REG_GET(mixer, cad, SI3055_GPIO_PIN_STATUS, &a, &b);
87
a |= 0x1; /* Set Off-Hook bit */
91
a &= ~0x1; /* Unset Off-Hook bit */
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);
99
void hdaudio_si3055_endpoint_init(hdaudio_mixer_t *mixer, int cad)
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. */
107
/* Output and input stream numbers. */
108
int playback_stream_num, recording_stream_num;
111
DDB(cmn_err(CE_CONT, "hdaudio_si3055_endpoint_init got called.\n"));
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);
118
/* Set 9600Hz as the initial line sampling rate.
119
* It can be changed later when desired.
121
SI3055_REG_SET(mixer, cad, SI3055_LINE_RATE, 9600);
123
/* Assign the "unused" value to the playback and recording
124
* stream descriptors (ref. HDAudio_03.pdf, page 40).
126
SI3055_REG_SET(mixer, cad, SI3055_HDA_STREAMS, 0x0000);
128
/* Write 0x0000 to the Extended Modem Status & Control register
129
* to power up the modem (ref. si3038.pdf, page 22).
131
SI3055_REG_SET(mixer, cad, SI3055_EXT_MODEM_STATUS, 0x0000);
133
/* Wait for the modem to complete power up. The lower 8 bits
134
* indicate that it is ready (ref. si3038.pdf, page 22).
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));
143
while(((a & 0xf) == 0) && --tmout);
147
cmn_err(CE_WARN, "si3055: power up timeout (status: %04x).\n", a);
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.
154
SI3055_REG_SET(mixer, cad, SI3055_GPIO_CONFIG, 0x0000);
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.
160
SI3055_REG_SET(mixer, cad, SI3055_LINE_CONFIG, 0x0010);
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");
168
/* Setup the output endpoint. */
169
codec->num_outendpoints = 1;
170
endpoint = &codec->outendpoints[0];
172
endpoint->iddle_stream = 0;
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;
190
/* Setup the input endpoint. */
191
codec->num_inendpoints = 1;
192
memcpy(&codec->inendpoints[0], endpoint, sizeof(*endpoint));
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;
198
endpoint = &codec->inendpoints[0];
199
recording_stream_num = ++mixer->num_inendpoints;
200
endpoint->stream_number = endpoint->default_stream_number = recording_stream_num;
202
/* Setup the stream numbers. */
203
SI3055_REG_SET(mixer, cad, SI3055_HDA_STREAMS, ((playback_stream_num << 4) << 8) |
204
(recording_stream_num << 4));