// Somewhat based on xerpi's CODEC driver for Linux
/*
* This file is part of GodMode9
* Copyright (C) 2017 Sergi Granell, Paul LaMendola
* Copyright (C) 2019 Wolfvak
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include "hw/codec.h"
#include "hw/spi.h"
#define CODEC_SPI_DEV 3
#define CPAD_THRESH (150)
/* SPI stuff */
static void CODEC_WriteRead(u32 *txb, u8 txl, u32 *rxb, u8 rxl)
{
SPI_XferInfo xfers[2];
xfers[0].buf = txb;
xfers[0].len = txl;
xfers[0].read = false;
xfers[1].buf = rxb;
xfers[1].len = rxl;
xfers[1].read = true;
SPI_DoXfer(CODEC_SPI_DEV, xfers, 2);
}
static void CODEC_RegSelect(u8 reg)
{
SPI_XferInfo xfer;
u32 cmd;
cmd = reg << 8;
xfer.buf = &cmd;
xfer.len = 2;
xfer.read = false;
SPI_DoXfer(CODEC_SPI_DEV, &xfer, 1);
}
static u8 CODEC_RegRead(u8 reg)
{
u32 cmd, ret;
cmd = (reg << 1) | 1;
CODEC_WriteRead(&cmd, 1, &ret, 1);
return ret;
}
static void CODEC_RegWrite(u8 reg, u8 val)
{
SPI_XferInfo xfer;
u32 cmd;
cmd = (val << 8) | (reg << 1);
xfer.buf = &cmd;
xfer.len = 2;
xfer.read = false;
SPI_DoXfer(CODEC_SPI_DEV, &xfer, 1);
}
static void CODEC_RegReadBuf(u8 reg, u32 *out, u8 size)
{
u32 cmd = (reg << 1) | 1;
CODEC_WriteRead(&cmd, 1, out, size);
}
static void CODEC_RegMask(u8 reg, u8 mask0, u8 mask1)
{
CODEC_RegWrite(reg, (CODEC_RegRead(reg) & ~mask1) | (mask0 & mask1));
}
void CODEC_Init(void)
{
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x24, 0x98);
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x26, 0x00);
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x25, 0x43);
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x24, 0x18);
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x17, 0x43);
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x19, 0x69);
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x1B, 0x80);
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x27, 0x11);
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x26, 0xEC);
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x24, 0x18);
CODEC_RegSelect(0x67);
CODEC_RegWrite(0x25, 0x53);
CODEC_RegSelect(0x67);
CODEC_RegMask(0x26, 0x80, 0x80);
CODEC_RegSelect(0x67);
CODEC_RegMask(0x24, 0x00, 0x80);
CODEC_RegSelect(0x67);
CODEC_RegMask(0x25, 0x10, 0x3C);
}
void CODEC_GetRawData(u32 *buffer)
{
CODEC_RegSelect(0x67);
CODEC_RegRead(0x26);
CODEC_RegSelect(0xFB);
CODEC_RegReadBuf(1, buffer, 0x34);
}
void CODEC_Get(CODEC_Input *input)
{
u32 raw_data_buf[0x34 / 4];
u8 *raw_data = (u8*)raw_data_buf;
s16 cpad_x, cpad_y;
bool ts_pressed;
CODEC_GetRawData(raw_data_buf);
cpad_x = ((raw_data[0x24] << 8 | raw_data[0x25]) & 0xFFF) - 2048;
cpad_y = ((raw_data[0x14] << 8 | raw_data[0x15]) & 0xFFF) - 2048;
// X axis is inverted
input->cpad_x = (abs(cpad_x) > CPAD_THRESH) ? -cpad_x : 0;
input->cpad_y = (abs(cpad_y) > CPAD_THRESH) ? cpad_y : 0;
ts_pressed = !(raw_data[0] & BIT(4));
if (ts_pressed) {
input->ts_x = (raw_data[0] << 8) | raw_data[1];
input->ts_y = (raw_data[10] << 8) | raw_data[11];
} else {
input->ts_x = 0xFFFF;
input->ts_y = 0xFFFF;
}
}