blob: 1dd059365a71840674fbe12bf3d9e532ae496785 [file] [log] [blame]
/*
* sound/soc/amlogic/auge/frhdmirx_hw.c
*
* Copyright (C) 2018 Amlogic, Inc. All rights reserved.
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include "frhdmirx_hw.h"
#include "regs.h"
#include "iomap.h"
void frhdmirx_enable(bool enable)
{
if (enable) {
audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0,
0x1 << 29,
0x1 << 29);
audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0,
0x1 << 28,
0x1 << 28);
} else
audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0,
0x3 << 28,
0x0 << 28);
audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0, 0x1 << 31, enable << 31);
}
/* source select
* 0: select spdif lane;
* 1: select PAO mode;
*/
void frhdmirx_src_select(int src)
{
audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0,
0x1 << 23,
(bool)src << 23);
}
static void frhdmirx_enable_irq_bits(int channels, int src)
{
int lane, int_bits = 0, i;
if (channels % 2)
lane = channels / 2 + 1;
else
lane = channels / 2;
/* interrupt bits */
if (src) { /* PAO mode */
int_bits = (
0x1 << INT_PAO_PAPB_MASK | /* find papb */
0x1 << INT_PAO_PCPD_MASK /* find pcpd changed */
);
} else { /* SPDIF Lane */
int lane_irq_bits = (0x1 << 7 | /* lane: find papb */
0x1 << 6 | /* lane: find papb */
0x1 << 5 | /* lane: find nonpcm to pcm */
0x1 << 4 | /* lane: find pcpd changed */
0x1 << 3 | /* lane: find ch status changed */
0x1 << 1 /* lane: find parity error */
);
for (i = 0; i < lane; i++)
int_bits |= (lane_irq_bits << i);
}
audiobus_write(EE_AUDIO_FRHDMIRX_CTRL2, int_bits);
}
void frhdmirx_clr_irq_bits(int channels, int src)
{
int lane, int_clr_mask = 0, i;
if (channels % 2)
lane = channels / 2 + 1;
else
lane = channels / 2;
/* interrupt bits */
if (src) { /* PAO mode */
int_clr_mask = (
0x1 << INT_PAO_PAPB_MASK | /* find papb */
0x1 << INT_PAO_PCPD_MASK /* find pcpd changed */
);
} else { /* SPDIF Lane */
int lane_irq_bits = (0x1 << 7 | /* lane: find papb */
0x1 << 6 | /* lane: find valid changed; */
0x1 << 5 | /* lane: find nonpcm to pcm */
0x1 << 4 | /* lane: find pcpd changed */
0x1 << 3 | /* lane: find ch status changed */
0x1 << 1 /* lane: find parity error */
);
for (i = 0; i < lane; i++)
int_clr_mask |= (lane_irq_bits << i);
}
audiobus_write(EE_AUDIO_FRHDMIRX_CTRL3, ~int_clr_mask);
audiobus_write(EE_AUDIO_FRHDMIRX_CTRL3, int_clr_mask);
audiobus_write(EE_AUDIO_FRHDMIRX_CTRL4, ~int_clr_mask);
audiobus_write(EE_AUDIO_FRHDMIRX_CTRL4, int_clr_mask);
}
void frhdmirx_ctrl(int channels, int src)
{
int lane, lane_mask = 0, i;
/* PAO mode */
if (src) {
audiobus_write(EE_AUDIO_FRHDMIRX_CTRL0,
0x1 << 22 | /* capture input by fall edge*/
0x1 << 8 | /* start detect PAPB */
0x4 << 4 /* chan status sel: pao pc/pd value */
);
} else {
if (channels % 2)
lane = channels / 2 + 1;
else
lane = channels / 2;
for (i = 0; i < lane; i++)
lane_mask |= (1 << i);
audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0,
0x1 << 30 | 0xf << 24 | 0x1 << 22 | 0x3 << 11,
0x1 << 30 | /* chnum_sel */
lane_mask << 24 | /* chnum_sel */
0x1 << 22 | /* clk_inv */
0x0 << 11 /* req_sel, Sync 4 spdifin by which */
);
}
/* nonpcm2pcm_th */
audiobus_write(EE_AUDIO_FRHDMIRX_CTRL1, 0xff << 20);
/* enable irq bits */
frhdmirx_enable_irq_bits(channels, src);
}
void frhdmirx_clr_PAO_irq_bits(void)
{
audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL4,
0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK,
0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK);
audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL4,
0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK,
0x0 << INT_PAO_PAPB_MASK | 0x0 << INT_PAO_PCPD_MASK);
}
unsigned int frhdmirx_get_ch_status0to31(void)
{
return (unsigned int)audiobus_read(EE_AUDIO_FRHDMIRX_STAT0);
}
unsigned int frhdmirx_get_chan_status_pc(void)
{
unsigned int val;
val = audiobus_read(EE_AUDIO_FRHDMIRX_STAT1);
return (val >> 16) & 0xff;
}