1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
/* $NetBSD: ac100.c,v 1.7 2021/01/27 02:29:48 thorpej Exp $ */
/*-
* Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "opt_fdt.h"
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ac100.c,v 1.7 2021/01/27 02:29:48 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/conf.h>
#include <sys/bus.h>
#include <sys/kmem.h>
#include <dev/clock_subr.h>
#include <dev/i2c/i2cvar.h>
#ifdef FDT
#include <dev/fdt/fdtvar.h>
#endif
#define AC100_CHIP_AUDIO_RST_REG 0x00
#define AC100_PLL_CTRL1_REG 0x02
#define AC100_PLL_CTRL2_REG 0x03
#define AC100_SYSCLK_CTRL_REG 0x04
#define AC100_MOD_RST_CTRL_REG 0x05
#define AC100_ADDA_SR_CTRL_REG 0x06
#define AC100_I2S1_LCK_CTRL_REG 0x10
#define AC100_I2S1_SDIN_CTRL_REG 0x11
#define AC100_I2S1_SDOUT_CTRL_REG 0x12
#define AC100_I2S1_DIG_MIXER_REG 0x13
#define AC100_I2S1_VOL_CTRL1_REG 0x14
#define AC100_I2S1_VOL_CTRL2_REG 0x15
#define AC100_I2S1_VOL_CTRL3_REG 0x16
#define AC100_I2S1_VOL_CTRL4_REG 0x17
#define AC100_I2S1_MXR_GAIN_REG 0x18
#define AC100_I2S2_CLK_CTRL_REG 0x20
#define AC100_I2S2_SDIN_CTRL_REG 0x21
#define AC100_I2S2_SDOUT_CTRL_REG 0x22
#define AC100_I2S2_DIG_MIXER_REG 0x23
#define AC100_I2S2_VOL_CTRL1_REG 0x24
#define AC100_I2S2_VOL_CTRL2_REG 0x26
#define AC100_I2S2_MXR_GAIN_REG 0x28
#define AC100_I2S3_CLK_CTRL_REG 0x30
#define AC100_I2S3_SDIN_CTRL_REG 0x31
#define AC100_I2S3_SDOUT_CTRL_REG 0x32
#define AC100_I2S3_SGP_CTRL_REG 0x33
#define AC100_ADC_DIG_CTRL_REG 0x40
#define AC100_RTC_RESET_REG 0xc6
#define AC100_RTC_CTRL_REG 0xc7
#define AC100_RTC_SEC_REG 0xc8
#define AC100_RTC_MIN_REG 0xc9
#define AC100_RTC_HOU_REG 0xca
#define AC100_RTC_WEE_REG 0xcb
#define AC100_RTC_DAY_REG 0xcc
#define AC100_RTC_MON_REG 0xcd
#define AC100_RTC_YEA_REG 0xce
#define AC100_RTC_UPD_TRIG_REG 0xcf
#define AC100_RTC_GP_REG(n) (0xe0 + (n))
#define AC100_RTC_CTRL_12H_24H_MODE __BIT(0)
#define AC100_RTC_UPD_TRIG_WRITE __BIT(15)
static const struct device_compatible_entry compat_data[] = {
{ .compat = "x-powers,ac100" },
DEVICE_COMPAT_EOL
};
struct ac100_softc {
device_t sc_dev;
i2c_tag_t sc_i2c;
i2c_addr_t sc_addr;
struct todr_chip_handle sc_todr;
};
static int ac100_match(device_t, cfdata_t, void *);
static void ac100_attach(device_t, device_t, void *);
static int ac100_rtc_gettime(todr_chip_handle_t, struct clock_ymdhms *);
static int ac100_rtc_settime(todr_chip_handle_t, struct clock_ymdhms *);
static int ac100_read(struct ac100_softc *, uint8_t, uint16_t *);
static int ac100_write(struct ac100_softc *, uint8_t, uint16_t);
CFATTACH_DECL_NEW(ac100ic, sizeof(struct ac100_softc),
ac100_match, ac100_attach, NULL, NULL);
static int
ac100_match(device_t parent, cfdata_t match, void *aux)
{
struct i2c_attach_args *ia = aux;
int match_result;
if (iic_use_direct_match(ia, match, compat_data, &match_result))
return match_result;
/* This device is direct-config only. */
return 0;
}
static void
ac100_attach(device_t parent, device_t self, void *aux)
{
struct ac100_softc *sc = device_private(self);
struct i2c_attach_args *ia = aux;
sc->sc_dev = self;
sc->sc_i2c = ia->ia_tag;
sc->sc_addr = ia->ia_addr;
aprint_naive("\n");
aprint_normal(": CODEC/RTC\n");
iic_acquire_bus(sc->sc_i2c, 0);
ac100_write(sc, AC100_RTC_CTRL_REG, AC100_RTC_CTRL_12H_24H_MODE);
iic_release_bus(sc->sc_i2c, 0);
sc->sc_todr.todr_gettime_ymdhms = ac100_rtc_gettime;
sc->sc_todr.todr_settime_ymdhms = ac100_rtc_settime;
sc->sc_todr.cookie = sc;
#ifdef FDT
const int phandle = ia->ia_cookie;
const int rtc_phandle = of_find_firstchild_byname(phandle, "rtc");
if (rtc_phandle > 0)
fdtbus_todr_attach(self, rtc_phandle, &sc->sc_todr);
#else
todr_attach(&sc->sc_todr);
#endif
}
static int
ac100_read(struct ac100_softc *sc, uint8_t reg, uint16_t *val)
{
return iic_smbus_read_word(sc->sc_i2c, sc->sc_addr, reg, val, 0);
}
static int
ac100_write(struct ac100_softc *sc, uint8_t reg, uint16_t val)
{
return iic_smbus_write_word(sc->sc_i2c, sc->sc_addr, reg, val, 0);
}
static int
ac100_rtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt)
{
struct ac100_softc *sc = tch->cookie;
uint16_t sec, min, hou, wee, day, mon, yea;
iic_acquire_bus(sc->sc_i2c, 0);
ac100_read(sc, AC100_RTC_SEC_REG, &sec);
ac100_read(sc, AC100_RTC_MIN_REG, &min);
ac100_read(sc, AC100_RTC_HOU_REG, &hou);
ac100_read(sc, AC100_RTC_WEE_REG, &wee);
ac100_read(sc, AC100_RTC_DAY_REG, &day);
ac100_read(sc, AC100_RTC_MON_REG, &mon);
ac100_read(sc, AC100_RTC_YEA_REG, &yea);
iic_release_bus(sc->sc_i2c, 0);
dt->dt_year = POSIX_BASE_YEAR + bcdtobin(yea & 0xff);
dt->dt_mon = bcdtobin(mon & 0x1f);
dt->dt_day = bcdtobin(day & 0x3f);
dt->dt_wday = bcdtobin(wee & 0x7);
dt->dt_hour = bcdtobin(hou & 0x3f);
dt->dt_min = bcdtobin(min & 0x7f);
dt->dt_sec = bcdtobin(sec & 0x7f);
return 0;
}
static int
ac100_rtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt)
{
struct ac100_softc *sc = tch->cookie;
iic_acquire_bus(sc->sc_i2c, 0);
ac100_write(sc, AC100_RTC_SEC_REG, bintobcd(dt->dt_sec) & 0x7f);
ac100_write(sc, AC100_RTC_MIN_REG, bintobcd(dt->dt_min) & 0x7f);
ac100_write(sc, AC100_RTC_HOU_REG, bintobcd(dt->dt_hour) & 0x3f);
ac100_write(sc, AC100_RTC_WEE_REG, bintobcd(dt->dt_wday) & 0x7);
ac100_write(sc, AC100_RTC_DAY_REG, bintobcd(dt->dt_day) & 0x3f);
ac100_write(sc, AC100_RTC_MON_REG, bintobcd(dt->dt_mon) & 0x1f);
ac100_write(sc, AC100_RTC_YEA_REG,
bintobcd(dt->dt_year - POSIX_BASE_YEAR) & 0xff);
ac100_write(sc, AC100_RTC_UPD_TRIG_REG, AC100_RTC_UPD_TRIG_WRITE);
iic_release_bus(sc->sc_i2c, 0);
return 0;
}
|