// SPDX-License-Identifier: GPL-2.0
//
// Socionext UniPhier AIO ALSA common driver.
//
// Copyright (c) 2016-2018 Socionext Inc.
#include <linux/bitfield.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "aio.h"
#include "aio-reg.h"
static u64 rb_cnt(u64 wr, u64 rd, u64 len)
{
if (rd <= wr)
return wr - rd;
else
return len - (rd - wr);
}
static u64 rb_cnt_to_end(u64 wr, u64 rd, u64 len)
{
if (rd <= wr)
return wr - rd;
else
return len - rd;
}
static u64 rb_space(u64 wr, u64 rd, u64 len)
{
if (rd <= wr)
return len - (wr - rd) - 8;
else
return rd - wr - 8;
}
static u64 rb_space_to_end(u64 wr, u64 rd, u64 len)
{
if (rd > wr)
return rd - wr - 8;
else if (rd > 0)
return len - wr;
else
return len - wr - 8;
}
u64 aio_rb_cnt(struct uniphier_aio_sub *sub)
{
return rb_cnt(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
}
u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub)
{
return rb_cnt_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
}
u64 aio_rb_space(struct uniphier_aio_sub *sub)
{
return rb_space(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
}
u64 aio_rb_space_to_end(struct uniphier_aio_sub *sub)
{
return rb_space_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
}
/**
* aio_iecout_set_enable - setup IEC output via SoC glue
* @chip: the AIO chip pointer
* @enable: false to stop the output, true to start
*
* Set enabled or disabled S/PDIF signal output to out of SoC via AOnIEC pins.
* This function need to call at driver startup.
*
* The regmap of SoC glue is specified by 'socionext,syscon' optional property
* of DT. This function has no effect if no property.
*/
void aio_iecout_set_enable(struct uniphier_aio_chip *chip, bool enable)
{
struct regmap *r = chip->regmap_sg;
if (!r)
return;
regmap_write(r, SG_AOUTEN, (enable) ? ~0 : 0);
}
/**
* aio_chip_set_pll - set frequency to audio PLL
* @chip: the AIO chip pointer
* @pll_id: PLL
* @freq: frequency in Hz, 0 is ignored
*
* Sets frequency of audio PLL. This function can be called anytime,
* but it takes time till PLL is locked.
*
* Return: Zero if successful, otherwise a negative value on error.
*/
int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
unsigned int freq)
{
struct device *dev = &chip->pdev->dev;
struct regmap *r = chip->regmap;
int shift;
u32 v;
/* Not change */
if (freq == 0)
return 0;
switch (pll_id) {
case AUD_PLL_A1:
shift = 0;
break;
case AUD_PLL_F1:
shift = 1;
break;
case AUD_PLL_A2:
shift = 2;
break;
case AUD_PLL_F2:
shift = 3;
break;
default:
dev_err(dev, "PLL(%d) not supported\n", pll_id);
return -EINVAL;
}