forked from Minki/linux
bc08f96b5f
The patch separates the IO function from the rt286. It is prepared to share for new chips that support the same IO function. Signed-off-by: Oder Chiou <oder_chiou@realtek.com> Signed-off-by: Mark Brown <broonie@kernel.org>
129 lines
2.9 KiB
C
129 lines
2.9 KiB
C
/*
|
|
* rl6347a.c - RL6347A class device shared support
|
|
*
|
|
* Copyright 2015 Realtek Semiconductor Corp.
|
|
*
|
|
* Author: Oder Chiou <oder_chiou@realtek.com>
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/init.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/dmi.h>
|
|
#include <linux/acpi.h>
|
|
#include <sound/core.h>
|
|
#include <sound/pcm.h>
|
|
#include <sound/pcm_params.h>
|
|
#include <sound/soc.h>
|
|
#include <sound/soc-dapm.h>
|
|
#include <sound/initval.h>
|
|
#include <sound/tlv.h>
|
|
#include <sound/jack.h>
|
|
#include <linux/workqueue.h>
|
|
#include <sound/hda_verbs.h>
|
|
|
|
#include "rl6347a.h"
|
|
|
|
int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value)
|
|
{
|
|
struct i2c_client *client = context;
|
|
struct rl6347a_priv *rl6347a = i2c_get_clientdata(client);
|
|
u8 data[4];
|
|
int ret, i;
|
|
|
|
/* handle index registers */
|
|
if (reg <= 0xff) {
|
|
rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
|
|
for (i = 0; i < rl6347a->index_cache_size; i++) {
|
|
if (reg == rl6347a->index_cache[i].reg) {
|
|
rl6347a->index_cache[i].def = value;
|
|
break;
|
|
}
|
|
|
|
}
|
|
reg = RL6347A_PROC_COEF;
|
|
}
|
|
|
|
data[0] = (reg >> 24) & 0xff;
|
|
data[1] = (reg >> 16) & 0xff;
|
|
/*
|
|
* 4 bit VID: reg should be 0
|
|
* 12 bit VID: value should be 0
|
|
* So we use an OR operator to handle it rather than use if condition.
|
|
*/
|
|
data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff);
|
|
data[3] = value & 0xff;
|
|
|
|
ret = i2c_master_send(client, data, 4);
|
|
|
|
if (ret == 4)
|
|
return 0;
|
|
else
|
|
pr_err("ret=%d\n", ret);
|
|
if (ret < 0)
|
|
return ret;
|
|
else
|
|
return -EIO;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rl6347a_hw_write);
|
|
|
|
int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value)
|
|
{
|
|
struct i2c_client *client = context;
|
|
struct i2c_msg xfer[2];
|
|
int ret;
|
|
__be32 be_reg;
|
|
unsigned int index, vid, buf = 0x0;
|
|
|
|
/* handle index registers */
|
|
if (reg <= 0xff) {
|
|
rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
|
|
reg = RL6347A_PROC_COEF;
|
|
}
|
|
|
|
reg = reg | 0x80000;
|
|
vid = (reg >> 8) & 0xfff;
|
|
|
|
if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) {
|
|
index = (reg >> 8) & 0xf;
|
|
reg = (reg & ~0xf0f) | index;
|
|
}
|
|
be_reg = cpu_to_be32(reg);
|
|
|
|
/* Write register */
|
|
xfer[0].addr = client->addr;
|
|
xfer[0].flags = 0;
|
|
xfer[0].len = 4;
|
|
xfer[0].buf = (u8 *)&be_reg;
|
|
|
|
/* Read data */
|
|
xfer[1].addr = client->addr;
|
|
xfer[1].flags = I2C_M_RD;
|
|
xfer[1].len = 4;
|
|
xfer[1].buf = (u8 *)&buf;
|
|
|
|
ret = i2c_transfer(client->adapter, xfer, 2);
|
|
if (ret < 0)
|
|
return ret;
|
|
else if (ret != 2)
|
|
return -EIO;
|
|
|
|
*value = be32_to_cpu(buf);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rl6347a_hw_read);
|
|
|
|
MODULE_DESCRIPTION("RL6347A class device shared support");
|
|
MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
|
|
MODULE_LICENSE("GPL v2");
|