1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * C-Media CMI8788 driver - helper functions 4 * 5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 6 */ 7 8 #include <linux/delay.h> 9 #include <linux/sched.h> 10 #include <linux/export.h> 11 #include <linux/io.h> 12 #include <sound/core.h> 13 #include <sound/mpu401.h> 14 #include "oxygen.h" 15 16 u8 oxygen_read8(struct oxygen *chip, unsigned int reg) 17 { 18 return inb(chip->addr + reg); 19 } 20 EXPORT_SYMBOL(oxygen_read8); 21 22 u16 oxygen_read16(struct oxygen *chip, unsigned int reg) 23 { 24 return inw(chip->addr + reg); 25 } 26 EXPORT_SYMBOL(oxygen_read16); 27 28 u32 oxygen_read32(struct oxygen *chip, unsigned int reg) 29 { 30 return inl(chip->addr + reg); 31 } 32 EXPORT_SYMBOL(oxygen_read32); 33 34 void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value) 35 { 36 outb(value, chip->addr + reg); 37 chip->saved_registers._8[reg] = value; 38 } 39 EXPORT_SYMBOL(oxygen_write8); 40 41 void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value) 42 { 43 outw(value, chip->addr + reg); 44 chip->saved_registers._16[reg / 2] = cpu_to_le16(value); 45 } 46 EXPORT_SYMBOL(oxygen_write16); 47 48 void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value) 49 { 50 outl(value, chip->addr + reg); 51 chip->saved_registers._32[reg / 4] = cpu_to_le32(value); 52 } 53 EXPORT_SYMBOL(oxygen_write32); 54 55 void oxygen_write8_masked(struct oxygen *chip, unsigned int reg, 56 u8 value, u8 mask) 57 { 58 u8 tmp = inb(chip->addr + reg); 59 tmp &= ~mask; 60 tmp |= value & mask; 61 outb(tmp, chip->addr + reg); 62 chip->saved_registers._8[reg] = tmp; 63 } 64 EXPORT_SYMBOL(oxygen_write8_masked); 65 66 void oxygen_write16_masked(struct oxygen *chip, unsigned int reg, 67 u16 value, u16 mask) 68 { 69 u16 tmp = inw(chip->addr + reg); 70 tmp &= ~mask; 71 tmp |= value & mask; 72 outw(tmp, chip->addr + reg); 73 chip->saved_registers._16[reg / 2] = cpu_to_le16(tmp); 74 } 75 EXPORT_SYMBOL(oxygen_write16_masked); 76 77 void oxygen_write32_masked(struct oxygen *chip, unsigned int reg, 78 u32 value, u32 mask) 79 { 80 u32 tmp = inl(chip->addr + reg); 81 tmp &= ~mask; 82 tmp |= value & mask; 83 outl(tmp, chip->addr + reg); 84 chip->saved_registers._32[reg / 4] = cpu_to_le32(tmp); 85 } 86 EXPORT_SYMBOL(oxygen_write32_masked); 87 88 static int oxygen_ac97_wait(struct oxygen *chip, unsigned int mask) 89 { 90 u8 status = 0; 91 92 /* 93 * Reading the status register also clears the bits, so we have to save 94 * the read bits in status. 95 */ 96 wait_event_timeout(chip->ac97_waitqueue, 97 ({ status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS); 98 status & mask; }), 99 msecs_to_jiffies(1) + 1); 100 /* 101 * Check even after a timeout because this function should not require 102 * the AC'97 interrupt to be enabled. 103 */ 104 status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS); 105 return status & mask ? 0 : -EIO; 106 } 107 108 /* 109 * About 10% of AC'97 register reads or writes fail to complete, but even those 110 * where the controller indicates completion aren't guaranteed to have actually 111 * happened. 112 * 113 * It's hard to assign blame to either the controller or the codec because both 114 * were made by C-Media ... 115 */ 116 117 void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, 118 unsigned int index, u16 data) 119 { 120 unsigned int count, succeeded; 121 u32 reg; 122 123 reg = data; 124 reg |= index << OXYGEN_AC97_REG_ADDR_SHIFT; 125 reg |= OXYGEN_AC97_REG_DIR_WRITE; 126 reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT; 127 succeeded = 0; 128 for (count = 5; count > 0; --count) { 129 udelay(5); 130 oxygen_write32(chip, OXYGEN_AC97_REGS, reg); 131 /* require two "completed" writes, just to be sure */ 132 if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 && 133 ++succeeded >= 2) { 134 chip->saved_ac97_registers[codec][index / 2] = data; 135 return; 136 } 137 } 138 dev_err(chip->card->dev, "AC'97 write timeout\n"); 139 } 140 EXPORT_SYMBOL(oxygen_write_ac97); 141 142 u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec, 143 unsigned int index) 144 { 145 unsigned int count; 146 unsigned int last_read = UINT_MAX; 147 u32 reg; 148 149 reg = index << OXYGEN_AC97_REG_ADDR_SHIFT; 150 reg |= OXYGEN_AC97_REG_DIR_READ; 151 reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT; 152 for (count = 5; count > 0; --count) { 153 udelay(5); 154 oxygen_write32(chip, OXYGEN_AC97_REGS, reg); 155 udelay(10); 156 if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_READ_DONE) >= 0) { 157 u16 value = oxygen_read16(chip, OXYGEN_AC97_REGS); 158 /* we require two consecutive reads of the same value */ 159 if (value == last_read) 160 return value; 161 last_read = value; 162 /* 163 * Invert the register value bits to make sure that two 164 * consecutive unsuccessful reads do not return the same 165 * value. 166 */ 167 reg ^= 0xffff; 168 } 169 } 170 dev_err(chip->card->dev, "AC'97 read timeout on codec %u\n", codec); 171 return 0; 172 } 173 EXPORT_SYMBOL(oxygen_read_ac97); 174 175 void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec, 176 unsigned int index, u16 data, u16 mask) 177 { 178 u16 value = oxygen_read_ac97(chip, codec, index); 179 value &= ~mask; 180 value |= data & mask; 181 oxygen_write_ac97(chip, codec, index, value); 182 } 183 EXPORT_SYMBOL(oxygen_write_ac97_masked); 184 185 static int oxygen_wait_spi(struct oxygen *chip) 186 { 187 unsigned int count; 188 189 /* 190 * Higher timeout to be sure: 200 us; 191 * actual transaction should not need more than 40 us. 192 */ 193 for (count = 50; count > 0; count--) { 194 udelay(4); 195 if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & 196 OXYGEN_SPI_BUSY) == 0) 197 return 0; 198 } 199 dev_err(chip->card->dev, "oxygen: SPI wait timeout\n"); 200 return -EIO; 201 } 202 203 int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data) 204 { 205 /* 206 * We need to wait AFTER initiating the SPI transaction, 207 * otherwise read operations will not work. 208 */ 209 oxygen_write8(chip, OXYGEN_SPI_DATA1, data); 210 oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8); 211 if (control & OXYGEN_SPI_DATA_LENGTH_3) 212 oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16); 213 oxygen_write8(chip, OXYGEN_SPI_CONTROL, control); 214 return oxygen_wait_spi(chip); 215 } 216 EXPORT_SYMBOL(oxygen_write_spi); 217 218 void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data) 219 { 220 /* should not need more than about 300 us */ 221 msleep(1); 222 223 oxygen_write8(chip, OXYGEN_2WIRE_MAP, map); 224 oxygen_write8(chip, OXYGEN_2WIRE_DATA, data); 225 oxygen_write8(chip, OXYGEN_2WIRE_CONTROL, 226 device | OXYGEN_2WIRE_DIR_WRITE); 227 } 228 EXPORT_SYMBOL(oxygen_write_i2c); 229 230 static void _write_uart(struct oxygen *chip, unsigned int port, u8 data) 231 { 232 if (oxygen_read8(chip, OXYGEN_MPU401 + 1) & MPU401_TX_FULL) 233 msleep(1); 234 oxygen_write8(chip, OXYGEN_MPU401 + port, data); 235 } 236 237 void oxygen_reset_uart(struct oxygen *chip) 238 { 239 _write_uart(chip, 1, MPU401_RESET); 240 msleep(1); /* wait for ACK */ 241 _write_uart(chip, 1, MPU401_ENTER_UART); 242 } 243 EXPORT_SYMBOL(oxygen_reset_uart); 244 245 void oxygen_write_uart(struct oxygen *chip, u8 data) 246 { 247 _write_uart(chip, 0, data); 248 } 249 EXPORT_SYMBOL(oxygen_write_uart); 250 251 u16 oxygen_read_eeprom(struct oxygen *chip, unsigned int index) 252 { 253 unsigned int timeout; 254 255 oxygen_write8(chip, OXYGEN_EEPROM_CONTROL, 256 index | OXYGEN_EEPROM_DIR_READ); 257 for (timeout = 0; timeout < 100; ++timeout) { 258 udelay(1); 259 if (!(oxygen_read8(chip, OXYGEN_EEPROM_STATUS) 260 & OXYGEN_EEPROM_BUSY)) 261 break; 262 } 263 return oxygen_read16(chip, OXYGEN_EEPROM_DATA); 264 } 265 266 void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value) 267 { 268 unsigned int timeout; 269 270 oxygen_write16(chip, OXYGEN_EEPROM_DATA, value); 271 oxygen_write8(chip, OXYGEN_EEPROM_CONTROL, 272 index | OXYGEN_EEPROM_DIR_WRITE); 273 for (timeout = 0; timeout < 10; ++timeout) { 274 msleep(1); 275 if (!(oxygen_read8(chip, OXYGEN_EEPROM_STATUS) 276 & OXYGEN_EEPROM_BUSY)) 277 return; 278 } 279 dev_err(chip->card->dev, "EEPROM write timeout\n"); 280 } 281
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.