1 // SPDX-License-Identifier: GPL-2.0-only 1 2 /* 3 * C-Media CMI8788 driver - helper functions 4 * 5 * Copyright (c) Clemens Ladisch <clemens@ladi 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 17 { 18 return inb(chip->addr + reg); 19 } 20 EXPORT_SYMBOL(oxygen_read8); 21 22 u16 oxygen_read16(struct oxygen *chip, unsigne 23 { 24 return inw(chip->addr + reg); 25 } 26 EXPORT_SYMBOL(oxygen_read16); 27 28 u32 oxygen_read32(struct oxygen *chip, unsigne 29 { 30 return inl(chip->addr + reg); 31 } 32 EXPORT_SYMBOL(oxygen_read32); 33 34 void oxygen_write8(struct oxygen *chip, unsign 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, unsig 42 { 43 outw(value, chip->addr + reg); 44 chip->saved_registers._16[reg / 2] = c 45 } 46 EXPORT_SYMBOL(oxygen_write16); 47 48 void oxygen_write32(struct oxygen *chip, unsig 49 { 50 outl(value, chip->addr + reg); 51 chip->saved_registers._32[reg / 4] = c 52 } 53 EXPORT_SYMBOL(oxygen_write32); 54 55 void oxygen_write8_masked(struct oxygen *chip, 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 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] = c 74 } 75 EXPORT_SYMBOL(oxygen_write16_masked); 76 77 void oxygen_write32_masked(struct oxygen *chip 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] = c 85 } 86 EXPORT_SYMBOL(oxygen_write32_masked); 87 88 static int oxygen_ac97_wait(struct oxygen *chi 89 { 90 u8 status = 0; 91 92 /* 93 * Reading the status register also cl 94 * the read bits in status. 95 */ 96 wait_event_timeout(chip->ac97_waitqueu 97 ({ status |= oxygen 98 status & mask; } 99 msecs_to_jiffies(1) 100 /* 101 * Check even after a timeout because 102 * the AC'97 interrupt to be enabled. 103 */ 104 status |= oxygen_read8(chip, OXYGEN_AC 105 return status & mask ? 0 : -EIO; 106 } 107 108 /* 109 * About 10% of AC'97 register reads or writes 110 * where the controller indicates completion a 111 * happened. 112 * 113 * It's hard to assign blame to either the con 114 * were made by C-Media ... 115 */ 116 117 void oxygen_write_ac97(struct oxygen *chip, un 118 unsigned int index, u16 119 { 120 unsigned int count, succeeded; 121 u32 reg; 122 123 reg = data; 124 reg |= index << OXYGEN_AC97_REG_ADDR_S 125 reg |= OXYGEN_AC97_REG_DIR_WRITE; 126 reg |= codec << OXYGEN_AC97_REG_CODEC_ 127 succeeded = 0; 128 for (count = 5; count > 0; --count) { 129 udelay(5); 130 oxygen_write32(chip, OXYGEN_AC 131 /* require two "completed" wri 132 if (oxygen_ac97_wait(chip, OXY 133 ++succeeded >= 2) { 134 chip->saved_ac97_regis 135 return; 136 } 137 } 138 dev_err(chip->card->dev, "AC'97 write 139 } 140 EXPORT_SYMBOL(oxygen_write_ac97); 141 142 u16 oxygen_read_ac97(struct oxygen *chip, unsi 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_SH 150 reg |= OXYGEN_AC97_REG_DIR_READ; 151 reg |= codec << OXYGEN_AC97_REG_CODEC_ 152 for (count = 5; count > 0; --count) { 153 udelay(5); 154 oxygen_write32(chip, OXYGEN_AC 155 udelay(10); 156 if (oxygen_ac97_wait(chip, OXY 157 u16 value = oxygen_rea 158 /* we require two cons 159 if (value == last_read 160 return value; 161 last_read = value; 162 /* 163 * Invert the register 164 * consecutive unsucce 165 * value. 166 */ 167 reg ^= 0xffff; 168 } 169 } 170 dev_err(chip->card->dev, "AC'97 read t 171 return 0; 172 } 173 EXPORT_SYMBOL(oxygen_read_ac97); 174 175 void oxygen_write_ac97_masked(struct oxygen *c 176 unsigned int ind 177 { 178 u16 value = oxygen_read_ac97(chip, cod 179 value &= ~mask; 180 value |= data & mask; 181 oxygen_write_ac97(chip, codec, index, 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 192 */ 193 for (count = 50; count > 0; count--) { 194 udelay(4); 195 if ((oxygen_read8(chip, OXYGEN 196 197 return 0; 198 } 199 dev_err(chip->card->dev, "oxygen: SPI 200 return -EIO; 201 } 202 203 int oxygen_write_spi(struct oxygen *chip, u8 c 204 { 205 /* 206 * We need to wait AFTER initiating th 207 * otherwise read operations will not 208 */ 209 oxygen_write8(chip, OXYGEN_SPI_DATA1, 210 oxygen_write8(chip, OXYGEN_SPI_DATA2, 211 if (control & OXYGEN_SPI_DATA_LENGTH_3 212 oxygen_write8(chip, OXYGEN_SPI 213 oxygen_write8(chip, OXYGEN_SPI_CONTROL 214 return oxygen_wait_spi(chip); 215 } 216 EXPORT_SYMBOL(oxygen_write_spi); 217 218 void oxygen_write_i2c(struct oxygen *chip, u8 219 { 220 /* should not need more than about 300 221 msleep(1); 222 223 oxygen_write8(chip, OXYGEN_2WIRE_MAP, 224 oxygen_write8(chip, OXYGEN_2WIRE_DATA, 225 oxygen_write8(chip, OXYGEN_2WIRE_CONTR 226 device | OXYGEN_2WIRE_DI 227 } 228 EXPORT_SYMBOL(oxygen_write_i2c); 229 230 static void _write_uart(struct oxygen *chip, u 231 { 232 if (oxygen_read8(chip, OXYGEN_MPU401 + 233 msleep(1); 234 oxygen_write8(chip, OXYGEN_MPU401 + po 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 246 { 247 _write_uart(chip, 0, data); 248 } 249 EXPORT_SYMBOL(oxygen_write_uart); 250 251 u16 oxygen_read_eeprom(struct oxygen *chip, un 252 { 253 unsigned int timeout; 254 255 oxygen_write8(chip, OXYGEN_EEPROM_CONT 256 index | OXYGEN_EEPROM_DI 257 for (timeout = 0; timeout < 100; ++tim 258 udelay(1); 259 if (!(oxygen_read8(chip, OXYGE 260 & OXYGEN_EEPROM_BUSY)) 261 break; 262 } 263 return oxygen_read16(chip, OXYGEN_EEPR 264 } 265 266 void oxygen_write_eeprom(struct oxygen *chip, 267 { 268 unsigned int timeout; 269 270 oxygen_write16(chip, OXYGEN_EEPROM_DAT 271 oxygen_write8(chip, OXYGEN_EEPROM_CONT 272 index | OXYGEN_EEPROM_DI 273 for (timeout = 0; timeout < 10; ++time 274 msleep(1); 275 if (!(oxygen_read8(chip, OXYGE 276 & OXYGEN_EEPROM_BUSY)) 277 return; 278 } 279 dev_err(chip->card->dev, "EEPROM write 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.