diff --git a/radio/src/drivers/tas2505.cpp b/radio/src/drivers/tas2505.cpp new file mode 100644 index 000000000..50a002d75 --- /dev/null +++ b/radio/src/drivers/tas2505.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "tas2505.h" +#include "stm32_i2s.h" +#include "timers_driver.h" + +#include "debug.h" + +#define TAS2505_NDAC_ENABLE (1U << 7) +#define TAS2505_MDAC_ENABLE (1U << 7) +#define TAS2505_MASTER_REF_ENABLE (1U << 4) +#define TAS2505_HPL_OUT_UP (1U << 5) +#define TAS2505_MIXER_P_TO_HP (1U << 2) + +static int tas2505_i2c_write(tas2505_t* dev, uint16_t reg, uint8_t value) +{ + if (!dev->addr) return -1; + return i2c_write(dev->bus, dev->addr, reg, 1, (uint8_t*)&value, sizeof(value)); +} + +static int tas2505_write_reg(tas2505_t* dev, uint16_t reg, uint8_t value) +{ + uint8_t page = reg >> 8; + if (tas2505_i2c_write(dev, 0, page) < 0) return -1; + return tas2505_i2c_write(dev, reg & 0xFF, value); +} + +static void tas2505_delay(uint32_t ms) +{ + uint32_t start = timersGetMsTick(); + while (timersGetMsTick() - start < ms) {} +} + +int tas2505_probe(tas2505_t* dev, etx_i2c_bus_t bus, uint16_t addr) +{ + dev->bus = 0; + dev->addr = 0; + + if (i2c_init(bus) < 0) { + TRACE("TAS2505 bus init error"); + return -1; + } + + if (i2c_dev_ready(bus, addr) < 0) { + TRACE("TAS2505 device init error"); + return -1; + } + + dev->bus = bus; + dev->addr = addr; + + return 0; +} + +int tas2505_init(tas2505_t* dev) +{ + // software reset + if (tas2505_write_reg(dev, TAS2505_RESET, 1) < 0) return -1; + tas2505_delay(2); + + if (dev->hp_drv < TAS2505_HP_DRV_MIN) { + dev->hp_drv = TAS2505_HP_DRV_MIN; + } else if (dev->hp_drv > TAS2505_HP_DRV_MAX) { + dev->hp_drv = TAS2505_HP_DRV_MAX; + } + + const struct { + uint16_t reg; + uint8_t value; + } params[] = { + {TAS2505_LDO_CTRL, 0}, + {TAS2505_CLKMUX, 0}, // MCLK -> CODEC_CLKIN + + {TAS2505_NDAC, (uint8_t)(TAS2505_NDAC_ENABLE | dev->ndac)}, + {TAS2505_MDAC, (uint8_t)(TAS2505_MDAC_ENABLE | dev->mdac)}, + {TAS2505_DOSRLSB, (uint8_t)(dev->dosr & 0xFF)}, + {TAS2505_DOSRMSB, (uint8_t)(dev->dosr >> 8)}, + + {TAS2505_IFACE1, 0}, // I2S, 16bit, BCLK in, WCLK in + {TAS2505_IFACE2, 0}, // Data slot offset 00 + {TAS2505_DACINSTRSET, 0b00000010}, // PRB_P2 + + {TAS2505_DACVOL, (uint8_t)dev->dac_vol}, + {TAS2505_DACSETUP1, 0b10010100}, // DAC on, left channel + {TAS2505_DACSETUP2, 0b00000100}, // DAC unmuted + + {TAS2505_REF_POR_LDO_BGAP_CTRL, TAS2505_MASTER_REF_ENABLE}, + {TAS2505_HPL_OUT, TAS2505_HPL_OUT_UP}, // HPL output ON + + {TAS2505_COMMON_MODE, 0}, // CM 0.9V + {TAS2505_HP_ROUTING, TAS2505_MIXER_P_TO_HP}, // enable HP + {TAS2505_HP_DRIVER, (uint8_t)(dev->hp_drv & 0x3F)}, + {TAS2505_HP_VOL, dev->hp_vol}, + + {TAS2505_SPKVOL1, dev->spk_vol}, + {TAS2505_SPKVOL2, dev->spk_drv}, + {TAS2505_SPKAMPCTRL1, 0b00000010}, // Spkr ON + }; + + for (unsigned i = 0; i < DIM(params); i++) { + uint16_t reg = params[i].reg; + uint8_t value = params[i].value; + if (tas2505_write_reg(dev, reg, value) < 0) { + return -1; + } + } + + return 0; +} diff --git a/radio/src/drivers/tas2505.h b/radio/src/drivers/tas2505.h new file mode 100644 index 000000000..cc119d362 --- /dev/null +++ b/radio/src/drivers/tas2505.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "hal/i2c_driver.h" + +#define TAS2505_REG(page, reg) ((page << 8) + reg) + +#define TAS2505_PAGECTL TAS2505_REG(0, 0) +#define TAS2505_RESET TAS2505_REG(0, 1) +#define TAS2505_CLKMUX TAS2505_REG(0, 4) +#define TAS2505_PLLPR TAS2505_REG(0, 5) +#define TAS2505_PLLJ TAS2505_REG(0, 6) +#define TAS2505_PLLDMSB TAS2505_REG(0, 7) +#define TAS2505_PLLDLSB TAS2505_REG(0, 8) +#define TAS2505_NDAC TAS2505_REG(0, 11) +#define TAS2505_MDAC TAS2505_REG(0, 12) +#define TAS2505_DOSRMSB TAS2505_REG(0, 13) +#define TAS2505_DOSRLSB TAS2505_REG(0, 14) +#define TAS2505_IFACE1 TAS2505_REG(0, 27) +#define TAS2505_IFACE2 TAS2505_REG(0, 28) +#define TAS2505_IFACE3 TAS2505_REG(0, 29) +#define TAS2505_BCLKNDIV TAS2505_REG(0, 30) +#define TAS2505_DACFLAG1 TAS2505_REG(0, 37) +#define TAS2505_DACFLAG2 TAS2505_REG(0, 38) +#define TAS2505_STICKYFLAG1 TAS2505_REG(0, 42) +#define TAS2505_INTFLAG1 TAS2505_REG(0, 43) +#define TAS2505_STICKYFLAG2 TAS2505_REG(0, 44) +#define TAS2505_INTFLAG2 TAS2505_REG(0, 46) +#define TAS2505_DACINSTRSET TAS2505_REG(0, 60) +#define TAS2505_DACSETUP1 TAS2505_REG(0, 63) +#define TAS2505_DACSETUP2 TAS2505_REG(0, 64) +#define TAS2505_DACVOL TAS2505_REG(0, 65) +#define TAS2505_REF_POR_LDO_BGAP_CTRL TAS2505_REG(1, 1) +#define TAS2505_LDO_CTRL TAS2505_REG(1, 2) +#define TAS2505_PLAYBACKCONF1 TAS2505_REG(1, 3) +#define TAS2505_HPL_OUT TAS2505_REG(1, 9) +#define TAS2505_COMMON_MODE TAS2505_REG(1, 10) +#define TAS2505_HP_ROUTING TAS2505_REG(1, 12) +#define TAS2505_HP_DRIVER TAS2505_REG(1, 16) +#define TAS2505_HP_VOL TAS2505_REG(1, 22) +#define TAS2505_MIXER_CTRL TAS2505_REG(1, 24) +#define TAS2505_SPKAMPCTRL1 TAS2505_REG(1, 45) +#define TAS2505_SPKVOL1 TAS2505_REG(1, 46) +#define TAS2505_SPKVOL2 TAS2505_REG(1, 48) +#define TAS2505_DACANLGAINFLAG TAS2505_REG(1, 63) + +#define TAS2505_SPK_DRV_MUTED (0U << 4) +#define TAS2505_SPK_DRV_6_DB (1U << 4) +#define TAS2505_SPK_DRV_12_DB (2U << 4) +#define TAS2505_SPK_DRV_18_DB (3U << 4) +#define TAS2505_SPK_DRV_24_DB (4U << 4) +#define TAS2505_SPK_DRV_32_DB (5U << 4) + +#define TAS2505_HP_DRV_MIN -5 +#define TAS2505_HP_DRV_MAX 29 + +typedef struct { + etx_i2c_bus_t bus; + uint16_t addr; + + uint8_t ndac; + uint8_t mdac; + uint16_t dosr; + + int8_t dac_vol; + + int8_t hp_drv; + uint8_t hp_vol; + + uint8_t spk_drv; + uint8_t spk_vol; + +} tas2505_t; + +int tas2505_probe(tas2505_t* dev, etx_i2c_bus_t bus, uint16_t addr); +int tas2505_init(tas2505_t* dev);