0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/init.h>
0014 #include <linux/device.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/err.h>
0018 #include <linux/clk.h>
0019 #include <linux/delay.h>
0020 #include <linux/io.h>
0021 #include <linux/slab.h>
0022 #include <linux/pm_runtime.h>
0023
0024 #include "omap-mcbsp.h"
0025 #include "omap-mcbsp-priv.h"
0026
0027
0028 #define OMAP_ST_REG_REV 0x00
0029 #define OMAP_ST_REG_SYSCONFIG 0x10
0030 #define OMAP_ST_REG_IRQSTATUS 0x18
0031 #define OMAP_ST_REG_IRQENABLE 0x1C
0032 #define OMAP_ST_REG_SGAINCR 0x24
0033 #define OMAP_ST_REG_SFIRCR 0x28
0034 #define OMAP_ST_REG_SSELCR 0x2C
0035
0036
0037 #define SIDETONEEN BIT(10)
0038
0039
0040 #define ST_AUTOIDLE BIT(0)
0041
0042
0043 #define ST_CH0GAIN(value) ((value) & 0xffff)
0044 #define ST_CH1GAIN(value) (((value) & 0xffff) << 16)
0045
0046
0047 #define ST_FIRCOEFF(value) ((value) & 0xffff)
0048
0049
0050 #define ST_SIDETONEEN BIT(0)
0051 #define ST_COEFFWREN BIT(1)
0052 #define ST_COEFFWRDONE BIT(2)
0053
0054 struct omap_mcbsp_st_data {
0055 void __iomem *io_base_st;
0056 struct clk *mcbsp_iclk;
0057 bool running;
0058 bool enabled;
0059 s16 taps[128];
0060 int nr_taps;
0061 s16 ch0gain;
0062 s16 ch1gain;
0063 };
0064
0065 static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
0066 {
0067 writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
0068 }
0069
0070 static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
0071 {
0072 return readl_relaxed(mcbsp->st_data->io_base_st + reg);
0073 }
0074
0075 #define MCBSP_ST_READ(mcbsp, reg) omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
0076 #define MCBSP_ST_WRITE(mcbsp, reg, val) \
0077 omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
0078
0079 static void omap_mcbsp_st_on(struct omap_mcbsp *mcbsp)
0080 {
0081 unsigned int w;
0082
0083 if (mcbsp->pdata->force_ick_on)
0084 mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
0085
0086
0087 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
0088 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
0089
0090
0091 w = MCBSP_READ(mcbsp, SSELCR);
0092 MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
0093
0094
0095 w = MCBSP_ST_READ(mcbsp, SSELCR);
0096 MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
0097 }
0098
0099 static void omap_mcbsp_st_off(struct omap_mcbsp *mcbsp)
0100 {
0101 unsigned int w;
0102
0103 w = MCBSP_ST_READ(mcbsp, SSELCR);
0104 MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
0105
0106 w = MCBSP_READ(mcbsp, SSELCR);
0107 MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
0108
0109
0110 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
0111 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
0112
0113 if (mcbsp->pdata->force_ick_on)
0114 mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
0115 }
0116
0117 static void omap_mcbsp_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
0118 {
0119 u16 val, i;
0120
0121 val = MCBSP_ST_READ(mcbsp, SSELCR);
0122
0123 if (val & ST_COEFFWREN)
0124 MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
0125
0126 MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
0127
0128 for (i = 0; i < 128; i++)
0129 MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
0130
0131 i = 0;
0132
0133 val = MCBSP_ST_READ(mcbsp, SSELCR);
0134 while (!(val & ST_COEFFWRDONE) && (++i < 1000))
0135 val = MCBSP_ST_READ(mcbsp, SSELCR);
0136
0137 MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
0138
0139 if (i == 1000)
0140 dev_err(mcbsp->dev, "McBSP FIR load error!\n");
0141 }
0142
0143 static void omap_mcbsp_st_chgain(struct omap_mcbsp *mcbsp)
0144 {
0145 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
0146
0147 MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) |
0148 ST_CH1GAIN(st_data->ch1gain));
0149 }
0150
0151 static int omap_mcbsp_st_set_chgain(struct omap_mcbsp *mcbsp, int channel,
0152 s16 chgain)
0153 {
0154 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
0155 int ret = 0;
0156
0157 if (!st_data)
0158 return -ENOENT;
0159
0160 spin_lock_irq(&mcbsp->lock);
0161 if (channel == 0)
0162 st_data->ch0gain = chgain;
0163 else if (channel == 1)
0164 st_data->ch1gain = chgain;
0165 else
0166 ret = -EINVAL;
0167
0168 if (st_data->enabled)
0169 omap_mcbsp_st_chgain(mcbsp);
0170 spin_unlock_irq(&mcbsp->lock);
0171
0172 return ret;
0173 }
0174
0175 static int omap_mcbsp_st_get_chgain(struct omap_mcbsp *mcbsp, int channel,
0176 s16 *chgain)
0177 {
0178 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
0179 int ret = 0;
0180
0181 if (!st_data)
0182 return -ENOENT;
0183
0184 spin_lock_irq(&mcbsp->lock);
0185 if (channel == 0)
0186 *chgain = st_data->ch0gain;
0187 else if (channel == 1)
0188 *chgain = st_data->ch1gain;
0189 else
0190 ret = -EINVAL;
0191 spin_unlock_irq(&mcbsp->lock);
0192
0193 return ret;
0194 }
0195
0196 static int omap_mcbsp_st_enable(struct omap_mcbsp *mcbsp)
0197 {
0198 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
0199
0200 if (!st_data)
0201 return -ENODEV;
0202
0203 spin_lock_irq(&mcbsp->lock);
0204 st_data->enabled = 1;
0205 omap_mcbsp_st_start(mcbsp);
0206 spin_unlock_irq(&mcbsp->lock);
0207
0208 return 0;
0209 }
0210
0211 static int omap_mcbsp_st_disable(struct omap_mcbsp *mcbsp)
0212 {
0213 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
0214 int ret = 0;
0215
0216 if (!st_data)
0217 return -ENODEV;
0218
0219 spin_lock_irq(&mcbsp->lock);
0220 omap_mcbsp_st_stop(mcbsp);
0221 st_data->enabled = 0;
0222 spin_unlock_irq(&mcbsp->lock);
0223
0224 return ret;
0225 }
0226
0227 static int omap_mcbsp_st_is_enabled(struct omap_mcbsp *mcbsp)
0228 {
0229 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
0230
0231 if (!st_data)
0232 return -ENODEV;
0233
0234 return st_data->enabled;
0235 }
0236
0237 static ssize_t st_taps_show(struct device *dev,
0238 struct device_attribute *attr, char *buf)
0239 {
0240 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
0241 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
0242 ssize_t status = 0;
0243 int i;
0244
0245 spin_lock_irq(&mcbsp->lock);
0246 for (i = 0; i < st_data->nr_taps; i++)
0247 status += sprintf(&buf[status], (i ? ", %d" : "%d"),
0248 st_data->taps[i]);
0249 if (i)
0250 status += sprintf(&buf[status], "\n");
0251 spin_unlock_irq(&mcbsp->lock);
0252
0253 return status;
0254 }
0255
0256 static ssize_t st_taps_store(struct device *dev,
0257 struct device_attribute *attr,
0258 const char *buf, size_t size)
0259 {
0260 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
0261 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
0262 int val, tmp, status, i = 0;
0263
0264 spin_lock_irq(&mcbsp->lock);
0265 memset(st_data->taps, 0, sizeof(st_data->taps));
0266 st_data->nr_taps = 0;
0267
0268 do {
0269 status = sscanf(buf, "%d%n", &val, &tmp);
0270 if (status < 0 || status == 0) {
0271 size = -EINVAL;
0272 goto out;
0273 }
0274 if (val < -32768 || val > 32767) {
0275 size = -EINVAL;
0276 goto out;
0277 }
0278 st_data->taps[i++] = val;
0279 buf += tmp;
0280 if (*buf != ',')
0281 break;
0282 buf++;
0283 } while (1);
0284
0285 st_data->nr_taps = i;
0286
0287 out:
0288 spin_unlock_irq(&mcbsp->lock);
0289
0290 return size;
0291 }
0292
0293 static DEVICE_ATTR_RW(st_taps);
0294
0295 static const struct attribute *sidetone_attrs[] = {
0296 &dev_attr_st_taps.attr,
0297 NULL,
0298 };
0299
0300 static const struct attribute_group sidetone_attr_group = {
0301 .attrs = (struct attribute **)sidetone_attrs,
0302 };
0303
0304 int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp)
0305 {
0306 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
0307
0308 if (st_data->enabled && !st_data->running) {
0309 omap_mcbsp_st_fir_write(mcbsp, st_data->taps);
0310 omap_mcbsp_st_chgain(mcbsp);
0311
0312 if (!mcbsp->free) {
0313 omap_mcbsp_st_on(mcbsp);
0314 st_data->running = 1;
0315 }
0316 }
0317
0318 return 0;
0319 }
0320
0321 int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp)
0322 {
0323 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
0324
0325 if (st_data->running) {
0326 if (!mcbsp->free) {
0327 omap_mcbsp_st_off(mcbsp);
0328 st_data->running = 0;
0329 }
0330 }
0331
0332 return 0;
0333 }
0334
0335 int omap_mcbsp_st_init(struct platform_device *pdev)
0336 {
0337 struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
0338 struct omap_mcbsp_st_data *st_data;
0339 struct resource *res;
0340 int ret;
0341
0342 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
0343 if (!res)
0344 return 0;
0345
0346 st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
0347 if (!st_data)
0348 return -ENOMEM;
0349
0350 st_data->mcbsp_iclk = devm_clk_get(mcbsp->dev, "ick");
0351 if (IS_ERR(st_data->mcbsp_iclk)) {
0352 dev_warn(mcbsp->dev,
0353 "Failed to get ick, sidetone might be broken\n");
0354 st_data->mcbsp_iclk = NULL;
0355 }
0356
0357 st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
0358 resource_size(res));
0359 if (!st_data->io_base_st)
0360 return -ENOMEM;
0361
0362 ret = devm_device_add_group(mcbsp->dev, &sidetone_attr_group);
0363 if (ret)
0364 return ret;
0365
0366 mcbsp->st_data = st_data;
0367
0368 return 0;
0369 }
0370
0371 static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
0372 struct snd_ctl_elem_info *uinfo)
0373 {
0374 struct soc_mixer_control *mc =
0375 (struct soc_mixer_control *)kcontrol->private_value;
0376 int max = mc->max;
0377 int min = mc->min;
0378
0379 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0380 uinfo->count = 1;
0381 uinfo->value.integer.min = min;
0382 uinfo->value.integer.max = max;
0383 return 0;
0384 }
0385
0386 #define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \
0387 static int \
0388 omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
0389 struct snd_ctl_elem_value *uc) \
0390 { \
0391 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
0392 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
0393 struct soc_mixer_control *mc = \
0394 (struct soc_mixer_control *)kc->private_value; \
0395 int max = mc->max; \
0396 int min = mc->min; \
0397 int val = uc->value.integer.value[0]; \
0398 \
0399 if (val < min || val > max) \
0400 return -EINVAL; \
0401 \
0402 \
0403 return omap_mcbsp_st_set_chgain(mcbsp, channel, val); \
0404 } \
0405 \
0406 static int \
0407 omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
0408 struct snd_ctl_elem_value *uc) \
0409 { \
0410 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
0411 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
0412 s16 chgain; \
0413 \
0414 if (omap_mcbsp_st_get_chgain(mcbsp, channel, &chgain)) \
0415 return -EAGAIN; \
0416 \
0417 uc->value.integer.value[0] = chgain; \
0418 return 0; \
0419 }
0420
0421 OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
0422 OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
0423
0424 static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
0425 struct snd_ctl_elem_value *ucontrol)
0426 {
0427 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0428 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
0429 u8 value = ucontrol->value.integer.value[0];
0430
0431 if (value == omap_mcbsp_st_is_enabled(mcbsp))
0432 return 0;
0433
0434 if (value)
0435 omap_mcbsp_st_enable(mcbsp);
0436 else
0437 omap_mcbsp_st_disable(mcbsp);
0438
0439 return 1;
0440 }
0441
0442 static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
0443 struct snd_ctl_elem_value *ucontrol)
0444 {
0445 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0446 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
0447
0448 ucontrol->value.integer.value[0] = omap_mcbsp_st_is_enabled(mcbsp);
0449 return 0;
0450 }
0451
0452 #define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
0453 xhandler_get, xhandler_put) \
0454 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
0455 .info = omap_mcbsp_st_info_volsw, \
0456 .get = xhandler_get, .put = xhandler_put, \
0457 .private_value = (unsigned long)&(struct soc_mixer_control) \
0458 {.min = xmin, .max = xmax} }
0459
0460 #define OMAP_MCBSP_ST_CONTROLS(port) \
0461 static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
0462 SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \
0463 omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \
0464 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
0465 -32768, 32767, \
0466 omap_mcbsp_get_st_ch0_volume, \
0467 omap_mcbsp_set_st_ch0_volume), \
0468 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
0469 -32768, 32767, \
0470 omap_mcbsp_get_st_ch1_volume, \
0471 omap_mcbsp_set_st_ch1_volume), \
0472 }
0473
0474 OMAP_MCBSP_ST_CONTROLS(2);
0475 OMAP_MCBSP_ST_CONTROLS(3);
0476
0477 int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
0478 {
0479 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0480 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
0481
0482 if (!mcbsp->st_data) {
0483 dev_warn(mcbsp->dev, "No sidetone data for port\n");
0484 return 0;
0485 }
0486
0487 switch (port_id) {
0488 case 2:
0489 return snd_soc_add_dai_controls(cpu_dai,
0490 omap_mcbsp2_st_controls,
0491 ARRAY_SIZE(omap_mcbsp2_st_controls));
0492 case 3:
0493 return snd_soc_add_dai_controls(cpu_dai,
0494 omap_mcbsp3_st_controls,
0495 ARRAY_SIZE(omap_mcbsp3_st_controls));
0496 default:
0497 dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
0498 break;
0499 }
0500
0501 return -EINVAL;
0502 }
0503 EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);