cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

stk1160-ac97.c (4136B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * STK1160 driver
      4 *
      5 * Copyright (C) 2012 Ezequiel Garcia
      6 * <elezegarcia--a.t--gmail.com>
      7 *
      8 * Copyright (C) 2016 Marcel Hasler
      9 * <mahasler--a.t--gmail.com>
     10 *
     11 * Based on Easycap driver by R.M. Thomas
     12 *	Copyright (C) 2010 R.M. Thomas
     13 *	<rmthomas--a.t--sciolus.org>
     14 */
     15
     16#include <linux/delay.h>
     17
     18#include "stk1160.h"
     19#include "stk1160-reg.h"
     20
     21static int stk1160_ac97_wait_transfer_complete(struct stk1160 *dev)
     22{
     23	unsigned long timeout = jiffies + msecs_to_jiffies(STK1160_AC97_TIMEOUT);
     24	u8 value;
     25
     26	/* Wait for AC97 transfer to complete */
     27	while (time_is_after_jiffies(timeout)) {
     28		stk1160_read_reg(dev, STK1160_AC97CTL_0, &value);
     29
     30		if (!(value & (STK1160_AC97CTL_0_CR | STK1160_AC97CTL_0_CW)))
     31			return 0;
     32
     33		usleep_range(50, 100);
     34	}
     35
     36	stk1160_err("AC97 transfer took too long, this should never happen!");
     37	return -EBUSY;
     38}
     39
     40static void stk1160_write_ac97(struct stk1160 *dev, u16 reg, u16 value)
     41{
     42	/* Set codec register address */
     43	stk1160_write_reg(dev, STK1160_AC97_ADDR, reg);
     44
     45	/* Set codec command */
     46	stk1160_write_reg(dev, STK1160_AC97_CMD, value & 0xff);
     47	stk1160_write_reg(dev, STK1160_AC97_CMD + 1, (value & 0xff00) >> 8);
     48
     49	/* Set command write bit to initiate write operation */
     50	stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c);
     51
     52	/* Wait for command write bit to be cleared */
     53	stk1160_ac97_wait_transfer_complete(dev);
     54}
     55
     56#ifdef DEBUG
     57static u16 stk1160_read_ac97(struct stk1160 *dev, u16 reg)
     58{
     59	u8 vall = 0;
     60	u8 valh = 0;
     61
     62	/* Set codec register address */
     63	stk1160_write_reg(dev, STK1160_AC97_ADDR, reg);
     64
     65	/* Set command read bit to initiate read operation */
     66	stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8b);
     67
     68	/* Wait for command read bit to be cleared */
     69	if (stk1160_ac97_wait_transfer_complete(dev) < 0)
     70		return 0;
     71
     72
     73	/* Retrieve register value */
     74	stk1160_read_reg(dev, STK1160_AC97_CMD, &vall);
     75	stk1160_read_reg(dev, STK1160_AC97_CMD + 1, &valh);
     76
     77	return (valh << 8) | vall;
     78}
     79
     80void stk1160_ac97_dump_regs(struct stk1160 *dev)
     81{
     82	u16 value;
     83
     84	value = stk1160_read_ac97(dev, 0x12); /* CD volume */
     85	stk1160_dbg("0x12 == 0x%04x", value);
     86
     87	value = stk1160_read_ac97(dev, 0x10); /* Line-in volume */
     88	stk1160_dbg("0x10 == 0x%04x", value);
     89
     90	value = stk1160_read_ac97(dev, 0x0e); /* MIC volume (mono) */
     91	stk1160_dbg("0x0e == 0x%04x", value);
     92
     93	value = stk1160_read_ac97(dev, 0x16); /* Aux volume */
     94	stk1160_dbg("0x16 == 0x%04x", value);
     95
     96	value = stk1160_read_ac97(dev, 0x1a); /* Record select */
     97	stk1160_dbg("0x1a == 0x%04x", value);
     98
     99	value = stk1160_read_ac97(dev, 0x02); /* Master volume */
    100	stk1160_dbg("0x02 == 0x%04x", value);
    101
    102	value = stk1160_read_ac97(dev, 0x1c); /* Record gain */
    103	stk1160_dbg("0x1c == 0x%04x", value);
    104}
    105#endif
    106
    107static int stk1160_has_audio(struct stk1160 *dev)
    108{
    109	u8 value;
    110
    111	stk1160_read_reg(dev, STK1160_POSV_L, &value);
    112	return !(value & STK1160_POSV_L_ACDOUT);
    113}
    114
    115static int stk1160_has_ac97(struct stk1160 *dev)
    116{
    117	u8 value;
    118
    119	stk1160_read_reg(dev, STK1160_POSV_L, &value);
    120	return !(value & STK1160_POSV_L_ACSYNC);
    121}
    122
    123void stk1160_ac97_setup(struct stk1160 *dev)
    124{
    125	if (!stk1160_has_audio(dev)) {
    126		stk1160_info("Device doesn't support audio, skipping AC97 setup.");
    127		return;
    128	}
    129
    130	if (!stk1160_has_ac97(dev)) {
    131		stk1160_info("Device uses internal 8-bit ADC, skipping AC97 setup.");
    132		return;
    133	}
    134
    135	/* Two-step reset AC97 interface and hardware codec */
    136	stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x94);
    137	stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c);
    138
    139	/* Set 16-bit audio data and choose L&R channel*/
    140	stk1160_write_reg(dev, STK1160_AC97CTL_1 + 2, 0x01);
    141	stk1160_write_reg(dev, STK1160_AC97CTL_1 + 3, 0x00);
    142
    143	/* Setup channels */
    144	stk1160_write_ac97(dev, 0x12, 0x8808); /* CD volume */
    145	stk1160_write_ac97(dev, 0x10, 0x0808); /* Line-in volume */
    146	stk1160_write_ac97(dev, 0x0e, 0x0008); /* MIC volume (mono) */
    147	stk1160_write_ac97(dev, 0x16, 0x0808); /* Aux volume */
    148	stk1160_write_ac97(dev, 0x1a, 0x0404); /* Record select */
    149	stk1160_write_ac97(dev, 0x02, 0x0000); /* Master volume */
    150	stk1160_write_ac97(dev, 0x1c, 0x0808); /* Record gain */
    151
    152#ifdef DEBUG
    153	stk1160_ac97_dump_regs(dev);
    154#endif
    155}