718 lines
19 KiB
C
718 lines
19 KiB
C
|
/*
|
||
|
* saf775x.c -- SAF775X Soc Audio driver
|
||
|
*
|
||
|
* Copyright (c) 2014-2018 NVIDIA CORPORATION. All rights reserved.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify it
|
||
|
* under the terms and conditions of the GNU General Public License,
|
||
|
* version 2, as published by the Free Software Foundation.
|
||
|
*
|
||
|
* This program is distributed in the hope 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 <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/i2c.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/spi/spi.h>
|
||
|
#include <linux/delay.h>
|
||
|
|
||
|
#include "saf775x_ioctl.h"
|
||
|
#include "audio_limits.h"
|
||
|
|
||
|
#define TEGRA_GPIO_D3_RESET
|
||
|
|
||
|
#if defined(TEGRA_GPIO_D3_RESET)
|
||
|
#include <linux/of.h>
|
||
|
#include <linux/of_gpio.h>
|
||
|
|
||
|
static int tmpm32x_rst_gpio;
|
||
|
#else
|
||
|
static struct i2c_client *tmpm32x;
|
||
|
static struct i2c_board_info tmpm32x_info = {
|
||
|
I2C_BOARD_INFO("tmpm32x", 0x61),
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
#define DRV_NAME "saf775x"
|
||
|
|
||
|
#define ENUM_EXT(xname, xhandler_get, xhandler_put,\
|
||
|
xstruct, xmin, xmax, xstep, xval) \
|
||
|
{ .name = xname, .arr = xstruct, \
|
||
|
.get = xhandler_get, .set = xhandler_put, \
|
||
|
.min = xmin, .max = xmax, .val = xval, .step = xstep}
|
||
|
|
||
|
struct saf775x_controls {
|
||
|
const unsigned char *name;
|
||
|
int min;
|
||
|
int max;
|
||
|
int val;
|
||
|
int step;
|
||
|
int *arr;
|
||
|
int (*get)(void *, struct saf775x_control_info *);
|
||
|
int (*set)(void *, int *, unsigned int *,
|
||
|
int, unsigned int);
|
||
|
};
|
||
|
|
||
|
struct saf775x_priv {
|
||
|
struct mutex mutex;
|
||
|
unsigned char msg_seq[48];
|
||
|
void *control_data;
|
||
|
struct saf775x_controls *controls;
|
||
|
unsigned int num_controls;
|
||
|
};
|
||
|
|
||
|
static int saf775x_soc_write_i2c(struct i2c_client *codec, unsigned int reg,
|
||
|
unsigned int val, unsigned int reg_len, unsigned int val_len)
|
||
|
{
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)i2c_get_clientdata(codec);
|
||
|
unsigned char *data = (unsigned char *)&saf775x->msg_seq;
|
||
|
int i, ret = 0;
|
||
|
|
||
|
mutex_lock(&saf775x->mutex);
|
||
|
|
||
|
if (reg_len) {
|
||
|
for (i = reg_len - 1; i >= 0; i--)
|
||
|
*data++ = ((reg & CHAR_BIT_MASK(i)) >>
|
||
|
BYTEPOS_IN_WORD(i));
|
||
|
|
||
|
}
|
||
|
if (val_len) {
|
||
|
for (i = val_len - 1; i >= 0; i--)
|
||
|
*data++ = ((val & CHAR_BIT_MASK(i)) >>
|
||
|
BYTEPOS_IN_WORD(i));
|
||
|
}
|
||
|
ret = i2c_master_send(saf775x->control_data,
|
||
|
saf775x->msg_seq, reg_len + val_len);
|
||
|
mutex_unlock(&saf775x->mutex);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_write_spi(struct spi_device *codec, unsigned int reg,
|
||
|
unsigned int val, unsigned int reg_len, unsigned int val_len)
|
||
|
{
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)spi_get_drvdata(codec);
|
||
|
unsigned char *data = (unsigned char *)&saf775x->msg_seq;
|
||
|
int i, ret = 0;
|
||
|
|
||
|
mutex_lock(&saf775x->mutex);
|
||
|
|
||
|
*data++ = reg_len + val_len + 1;
|
||
|
|
||
|
if (reg_len) {
|
||
|
for (i = reg_len - 1; i >= 0; i--)
|
||
|
*data++ = ((reg & CHAR_BIT_MASK(i)) >>
|
||
|
BYTEPOS_IN_WORD(i));
|
||
|
|
||
|
}
|
||
|
if (val_len) {
|
||
|
for (i = val_len - 1; i >= 0; i--)
|
||
|
*data++ = ((val & CHAR_BIT_MASK(i)) >>
|
||
|
BYTEPOS_IN_WORD(i));
|
||
|
}
|
||
|
ret = spi_write(saf775x->control_data,
|
||
|
saf775x->msg_seq, reg_len + val_len + 1);
|
||
|
mdelay(10);
|
||
|
mutex_unlock(&saf775x->mutex);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int saf775x_soc_write(void *codec, unsigned int reg,
|
||
|
unsigned int val, unsigned int reg_len, unsigned int val_len)
|
||
|
{
|
||
|
if (saf775x_get_active_if() == I2C) {
|
||
|
struct i2c_client *i2c = (struct i2c_client *)codec;
|
||
|
return saf775x_soc_write_i2c(i2c, reg, val, reg_len, val_len);
|
||
|
} else {
|
||
|
struct spi_device *spi = (struct spi_device *)codec;
|
||
|
return saf775x_soc_write_spi(spi, reg, val, reg_len, val_len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_write_keycode_i2c(struct i2c_client *codec,
|
||
|
unsigned int reg, unsigned char *val,
|
||
|
unsigned int reg_len, unsigned int val_len)
|
||
|
{
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)i2c_get_clientdata(codec);
|
||
|
unsigned char *data = (unsigned char *)&saf775x->msg_seq;
|
||
|
int i, ret = 0;
|
||
|
|
||
|
mutex_lock(&saf775x->mutex);
|
||
|
|
||
|
if (reg_len) {
|
||
|
for (i = reg_len - 1; i >= 0; i--)
|
||
|
*data++ = ((reg & CHAR_BIT_MASK(i)) >>
|
||
|
BYTEPOS_IN_WORD(i));
|
||
|
|
||
|
}
|
||
|
if (val_len) {
|
||
|
for (i = 0; i < val_len; i++)
|
||
|
*data++ = val[i];
|
||
|
}
|
||
|
ret = i2c_master_send(saf775x->control_data,
|
||
|
saf775x->msg_seq, reg_len + val_len);
|
||
|
mutex_unlock(&saf775x->mutex);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_write_keycode_spi(struct spi_device *codec,
|
||
|
unsigned int reg, unsigned char *val,
|
||
|
unsigned int reg_len, unsigned int val_len)
|
||
|
{
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)spi_get_drvdata(codec);
|
||
|
unsigned char *data = (unsigned char *)&saf775x->msg_seq;
|
||
|
int i, ret = 0;
|
||
|
|
||
|
mutex_lock(&saf775x->mutex);
|
||
|
|
||
|
*data++ = reg_len + val_len + 1;
|
||
|
|
||
|
if (reg_len) {
|
||
|
for (i = reg_len - 1; i >= 0; i--)
|
||
|
*data++ = ((reg & CHAR_BIT_MASK(i)) >>
|
||
|
BYTEPOS_IN_WORD(i));
|
||
|
|
||
|
}
|
||
|
if (val_len) {
|
||
|
for (i = 0; i < val_len; i++)
|
||
|
*data++ = val[i];
|
||
|
}
|
||
|
data = (unsigned char *)&saf775x->msg_seq;
|
||
|
ret = spi_write(saf775x->control_data,
|
||
|
saf775x->msg_seq, reg_len + val_len + 1);
|
||
|
mdelay(10);
|
||
|
mutex_unlock(&saf775x->mutex);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_write_keycode(void *codec, unsigned int reg,
|
||
|
unsigned char *val, unsigned int reg_len, unsigned int val_len)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
if (saf775x_get_active_if() == I2C)
|
||
|
ret = saf775x_soc_write_keycode_i2c((struct i2c_client *)codec,
|
||
|
reg, val, reg_len, val_len);
|
||
|
else
|
||
|
ret = saf775x_soc_write_keycode_spi((struct spi_device *)codec,
|
||
|
reg, val, reg_len, val_len);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
#if defined(CONFIG_SPI_MASTER)
|
||
|
static int saf775x_soc_flash_image(struct spi_device *codec,
|
||
|
char *image_data, unsigned int image_size)
|
||
|
{
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)spi_get_drvdata(codec);
|
||
|
|
||
|
int ret = 0;
|
||
|
|
||
|
mutex_lock(&saf775x->mutex);
|
||
|
ret = spi_write(saf775x->control_data, image_data, image_size);
|
||
|
mdelay(10);
|
||
|
mutex_unlock(&saf775x->mutex);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_read_status(struct spi_device *codec,
|
||
|
char *status, unsigned int size)
|
||
|
{
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)spi_get_drvdata(codec);
|
||
|
|
||
|
int ret = 0;
|
||
|
mutex_lock(&saf775x->mutex);
|
||
|
ret = spi_read(saf775x->control_data, status, size);
|
||
|
mdelay(10);
|
||
|
mutex_unlock(&saf775x->mutex);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
int saf775x_set_default_ctrl(
|
||
|
void *codec,
|
||
|
int *arr,
|
||
|
unsigned int *reg,
|
||
|
int val,
|
||
|
unsigned int num_reg) {
|
||
|
|
||
|
unsigned int *_reg;
|
||
|
unsigned int i = 0;
|
||
|
_reg = kmalloc(sizeof(unsigned int) * num_reg, GFP_KERNEL);
|
||
|
|
||
|
if (!_reg)
|
||
|
return -ENOMEM;
|
||
|
if (copy_from_user(_reg, reg, sizeof(unsigned int) * num_reg)) {
|
||
|
kfree(_reg);
|
||
|
return -EFAULT;
|
||
|
}
|
||
|
for (i = 0; i < num_reg; i++)
|
||
|
saf775x_soc_write(codec, _reg[i],
|
||
|
(unsigned int)arr[(val*num_reg) + i], 3, 2);
|
||
|
kfree(_reg);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
struct saf775x_controls ctrls[] = {
|
||
|
ENUM_EXT("pri-vol", NULL, saf775x_set_default_ctrl, saf775x_vol_level[0], 0, 23, 1, 0),
|
||
|
ENUM_EXT("sec-vol", NULL, saf775x_set_default_ctrl, saf775x_vol_level[0], 0, 23, 1, 0),
|
||
|
ENUM_EXT("sec2-vol", NULL, saf775x_set_default_ctrl, saf775x_vol_level[0], 0, 23, 1, 0),
|
||
|
ENUM_EXT("pri-bal-l", NULL, saf775x_set_default_ctrl, saf775x_bal_level[0], 0, 120, 10, 0),
|
||
|
ENUM_EXT("pri-bal-r", NULL, saf775x_set_default_ctrl, saf775x_bal_level[0], 0, 120, 10, 0),
|
||
|
ENUM_EXT("sec-bal-l", NULL, saf775x_set_default_ctrl, saf775x_bal_level[0], 0, 120, 10, 0),
|
||
|
ENUM_EXT("sec-bal-l", NULL, saf775x_set_default_ctrl, saf775x_bal_level[0], 0, 120, 10, 0),
|
||
|
ENUM_EXT("sec2-bal-r", NULL, saf775x_set_default_ctrl, saf775x_bal_level[0], 0, 120, 10, 0),
|
||
|
ENUM_EXT("sec2-bal-r", NULL, saf775x_set_default_ctrl, saf775x_bal_level[0], 0, 120, 10, 0),
|
||
|
ENUM_EXT("front-fad", NULL, saf775x_set_default_ctrl, saf775x_bal_level[0], 0, 120, 10, 0),
|
||
|
ENUM_EXT("rear-fad", NULL, saf775x_set_default_ctrl, saf775x_bal_level[0], 0, 120, 10, 0),
|
||
|
ENUM_EXT("swl-fad", NULL, saf775x_set_default_ctrl, saf775x_bal_level[0], 0, 120, 10, 0),
|
||
|
ENUM_EXT("swr-fad", NULL, saf775x_set_default_ctrl, saf775x_bal_level[0], 0, 120, 10, 0),
|
||
|
ENUM_EXT("pri-bas", NULL, saf775x_set_default_ctrl, saf775x_bas_level[0], -14, 24, 2, 0),
|
||
|
ENUM_EXT("sec-bas", NULL, saf775x_set_default_ctrl, saf775x_bas_level[0], -14, 24, 2, 0),
|
||
|
ENUM_EXT("sec2-bas", NULL, saf775x_set_default_ctrl, saf775x_bas_level[0], -14, 24, 2, 0),
|
||
|
ENUM_EXT("pri-mid", NULL, saf775x_set_default_ctrl, saf775x_mid_level[0], -14, 14, 2, 0),
|
||
|
ENUM_EXT("sec-mid", NULL, saf775x_set_default_ctrl, saf775x_mid_level[0], -14, 14, 2, 0),
|
||
|
ENUM_EXT("sec2-mid", NULL, saf775x_set_default_ctrl, saf775x_mid_level[0], -14, 14, 2, 0),
|
||
|
ENUM_EXT("pri-tre", NULL, saf775x_set_default_ctrl, saf775x_mid_level[0], -14, 14, 2, 0),
|
||
|
ENUM_EXT("sec-tre", NULL, saf775x_set_default_ctrl, saf775x_mid_level[0], -14, 14, 2, 0),
|
||
|
ENUM_EXT("sec2-tre", NULL, saf775x_set_default_ctrl, saf775x_mid_level[0], -14, 14, 2, 0),
|
||
|
ENUM_EXT("front-sign-l", NULL, saf775x_set_default_ctrl, saf775x_sign_level[0], 0, 1, 1, 0),
|
||
|
ENUM_EXT("front-sign-r", NULL, saf775x_set_default_ctrl, saf775x_sign_level[0], 0, 1, 1, 0),
|
||
|
ENUM_EXT("rear-sign-l", NULL, saf775x_set_default_ctrl, saf775x_sign_level[0], 0, 1, 1, 0),
|
||
|
ENUM_EXT("rear-sign-r", NULL, saf775x_set_default_ctrl, saf775x_sign_level[0], 0, 1, 1, 0),
|
||
|
ENUM_EXT("swl-sign-l", NULL, saf775x_set_default_ctrl, saf775x_sign_level[0], 0, 1, 1, 0),
|
||
|
ENUM_EXT("swr-sign-r", NULL, saf775x_set_default_ctrl, saf775x_sign_level[0], 0, 1, 1, 0),
|
||
|
ENUM_EXT("pri-mute", NULL, saf775x_set_default_ctrl, saf775x_mute_level[0], 0, 1, 1, 0),
|
||
|
ENUM_EXT("sec-mute", NULL, saf775x_set_default_ctrl, saf775x_mute_level[0], 0, 1, 1, 0),
|
||
|
ENUM_EXT("sec2-mute", NULL, saf775x_set_default_ctrl, saf775x_mute_level[0], 0, 1, 1, 0),
|
||
|
ENUM_EXT("pri-mute-rise", NULL, saf775x_set_default_ctrl, saf775x_mute_att_level[0], 10, 100, 10, 10),
|
||
|
ENUM_EXT("sec-mute-rise", NULL, saf775x_set_default_ctrl, saf775x_mute_att_level[0], 10, 100, 10, 10),
|
||
|
ENUM_EXT("sec2-mute-rise", NULL, saf775x_set_default_ctrl, saf775x_mute_att_level[0], 10, 100, 10, 10),
|
||
|
ENUM_EXT("pri-mute-fall", NULL, saf775x_set_default_ctrl, saf775x_mute_att_level[0], 10, 100, 10, 100),
|
||
|
ENUM_EXT("sec-mute-fall", NULL, saf775x_set_default_ctrl, saf775x_mute_att_level[0], 10, 100, 10, 100),
|
||
|
ENUM_EXT("sec2-mute-fall", NULL, saf775x_set_default_ctrl, saf775x_mute_att_level[0], 10, 100, 10, 100),
|
||
|
};
|
||
|
|
||
|
static int saf775x_soc_set_ctrl_i2c(struct i2c_client *codec, char *ctrl_name,
|
||
|
unsigned int *reg, int val,
|
||
|
unsigned int num_reg) {
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)i2c_get_clientdata(codec);
|
||
|
unsigned int i = 0;
|
||
|
struct saf775x_controls *c;
|
||
|
|
||
|
for (i = 0; i < saf775x->num_controls; i++) {
|
||
|
c = &saf775x->controls[i];
|
||
|
if (!strcmp(ctrl_name, c->name)) {
|
||
|
if (val > c->max)
|
||
|
val = c->max;
|
||
|
else if (val < c->min)
|
||
|
val = c->min;
|
||
|
else
|
||
|
;
|
||
|
|
||
|
c->val = val;
|
||
|
val = (val - c->min)/c->step;
|
||
|
c->set(codec, c->arr, reg, val, num_reg);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return -EFAULT;
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_set_ctrl_spi(struct spi_device *codec, char *ctrl_name,
|
||
|
unsigned int *reg, int val,
|
||
|
unsigned int num_reg) {
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)spi_get_drvdata(codec);
|
||
|
unsigned int i = 0;
|
||
|
struct saf775x_controls *c;
|
||
|
|
||
|
for (i = 0; i < saf775x->num_controls; i++) {
|
||
|
c = &saf775x->controls[i];
|
||
|
if (!strcmp(ctrl_name, c->name)) {
|
||
|
if (val > c->max)
|
||
|
val = c->max;
|
||
|
else if (val < c->min)
|
||
|
val = c->min;
|
||
|
else
|
||
|
;
|
||
|
|
||
|
c->val = val;
|
||
|
val = (val - c->min)/c->step;
|
||
|
c->set(codec, c->arr, reg, val, num_reg);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return -EFAULT;
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_set_ctrl(void *codec, char *ctrl_name,
|
||
|
unsigned int *reg, int val,
|
||
|
unsigned int num_reg) {
|
||
|
if (saf775x_get_active_if() == I2C) {
|
||
|
struct i2c_client *i2c = (struct i2c_client *)codec;
|
||
|
return saf775x_soc_set_ctrl_i2c(i2c, ctrl_name,
|
||
|
reg, val, num_reg);
|
||
|
} else {
|
||
|
struct spi_device *spi = (struct spi_device *)codec;
|
||
|
return saf775x_soc_set_ctrl_spi(spi, ctrl_name,
|
||
|
reg, val, num_reg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static int saf775x_soc_get_ctrl_i2c(struct i2c_client *codec,
|
||
|
struct saf775x_control_info *info) {
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)i2c_get_clientdata(codec);
|
||
|
unsigned int i = 0;
|
||
|
struct saf775x_controls *c;
|
||
|
|
||
|
for (i = 0; i < saf775x->num_controls; i++) {
|
||
|
c = &saf775x->controls[i];
|
||
|
if (!strcmp(info->name, c->name)) {
|
||
|
info->min = c->min;
|
||
|
info->max = c->max;
|
||
|
info->val = c->val;
|
||
|
info->step = c->step;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return -EFAULT;
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_get_ctrl_spi(struct spi_device *codec,
|
||
|
struct saf775x_control_info *info) {
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)spi_get_drvdata(codec);
|
||
|
unsigned int i = 0;
|
||
|
struct saf775x_controls *c;
|
||
|
|
||
|
for (i = 0; i < saf775x->num_controls; i++) {
|
||
|
c = &saf775x->controls[i];
|
||
|
if (!strcmp(info->name, c->name)) {
|
||
|
info->min = c->min;
|
||
|
info->max = c->max;
|
||
|
info->val = c->val;
|
||
|
info->step = c->step;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return -EFAULT;
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_get_ctrl(void *codec,
|
||
|
struct saf775x_control_info *info) {
|
||
|
if (saf775x_get_active_if() == I2C) {
|
||
|
struct i2c_client *i2c = (struct i2c_client *)codec;
|
||
|
return saf775x_soc_get_ctrl_i2c(i2c, info);
|
||
|
} else {
|
||
|
struct spi_device *spi = (struct spi_device *)codec;
|
||
|
return saf775x_soc_get_ctrl_spi(spi, info);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_read_i2c(struct i2c_client *codec,
|
||
|
unsigned char *val, unsigned int val_len)
|
||
|
{
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)i2c_get_clientdata(codec);
|
||
|
int ret = 0;
|
||
|
|
||
|
mutex_lock(&saf775x->mutex);
|
||
|
|
||
|
ret = i2c_master_recv(saf775x->control_data,
|
||
|
val, val_len);
|
||
|
mutex_unlock(&saf775x->mutex);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_read_spi(struct spi_device *codec,
|
||
|
unsigned char *val, unsigned int val_len)
|
||
|
{
|
||
|
struct saf775x_priv *saf775x =
|
||
|
(struct saf775x_priv *)spi_get_drvdata(codec);
|
||
|
int ret = 0;
|
||
|
|
||
|
mutex_lock(&saf775x->mutex);
|
||
|
|
||
|
ret = spi_read(saf775x->control_data,
|
||
|
val, val_len);
|
||
|
mdelay(10);
|
||
|
mutex_unlock(&saf775x->mutex);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int saf775x_soc_read(void *codec,
|
||
|
unsigned char *val, unsigned int val_len)
|
||
|
{
|
||
|
if (saf775x_get_active_if() == I2C) {
|
||
|
struct i2c_client *i2c = (struct i2c_client *)codec;
|
||
|
return saf775x_soc_read_i2c(i2c, val, val_len);
|
||
|
} else {
|
||
|
struct spi_device *spi = (struct spi_device *)codec;
|
||
|
return saf775x_soc_read_spi(spi, val, val_len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if defined(TEGRA_GPIO_D3_RESET)
|
||
|
static int saf775x_chip_reset(void)
|
||
|
{
|
||
|
int err = 0;
|
||
|
|
||
|
if (gpio_is_valid(tmpm32x_rst_gpio)) {
|
||
|
gpio_set_value_cansleep(tmpm32x_rst_gpio, 0);
|
||
|
msleep(10);
|
||
|
gpio_set_value_cansleep(tmpm32x_rst_gpio, 1);
|
||
|
msleep(100);
|
||
|
} else {
|
||
|
pr_info("reset dirana GPIO invalid, gpio= %d", tmpm32x_rst_gpio);
|
||
|
err = -EBADF;
|
||
|
}
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
static void saf775x_chip_get_rst_gpio(void)
|
||
|
{
|
||
|
struct device_node *np;
|
||
|
int err = 0;
|
||
|
|
||
|
np = of_find_compatible_node(NULL, NULL, "nvidia,tegra-saf775x");
|
||
|
if (NULL != np) {
|
||
|
tmpm32x_rst_gpio = of_get_named_gpio(np, "rst-gpio", 0);
|
||
|
pr_info("saf775x: rst-gpio:%d\n", tmpm32x_rst_gpio);
|
||
|
if (!gpio_is_valid(tmpm32x_rst_gpio)) {
|
||
|
pr_info("reset dirana GPIO get name failed, gpio= %d",
|
||
|
tmpm32x_rst_gpio);
|
||
|
} else {
|
||
|
err = gpio_request(tmpm32x_rst_gpio, "rst_gpio");
|
||
|
if (err)
|
||
|
pr_err("reset dirana GPIO request failed, err=%d\n", err);
|
||
|
else
|
||
|
gpio_direction_output(tmpm32x_rst_gpio, 1); /* set direction */
|
||
|
}
|
||
|
} else
|
||
|
pr_err("reset dirana GPIO get node failed, np= NULL\n");
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
static int saf775x_chip_reset(void)
|
||
|
{
|
||
|
int err;
|
||
|
tmpm32x = i2c_new_device(i2c_get_adapter(0),
|
||
|
&tmpm32x_info);
|
||
|
if (!tmpm32x)
|
||
|
pr_err(KERN_ERR "Cannot open i2c device TMPM32X\n");
|
||
|
unsigned char mcu_saf_775x_reset_low[3] = {0x30, 0x07, 0x0};
|
||
|
unsigned char mcu_saf_775x_reset_high[3] = {0x30, 0x07, 0x1};
|
||
|
i2c_master_send(tmpm32x, mcu_saf_775x_reset_low, 3);
|
||
|
msleep(10);
|
||
|
i2c_master_send(tmpm32x, mcu_saf_775x_reset_high, 3);
|
||
|
msleep(100);
|
||
|
i2c_unregister_device(tmpm32x);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||
|
static int saf775x_i2c_probe(struct i2c_client *client,
|
||
|
const struct i2c_device_id *id)
|
||
|
{
|
||
|
struct saf775x_priv *saf775x;
|
||
|
struct saf775x_device_interfaces *devifs = saf775x_get_devifs();
|
||
|
|
||
|
devifs->client = client;
|
||
|
|
||
|
saf775x = devm_kzalloc(&client->dev, sizeof(struct saf775x_priv),
|
||
|
GFP_KERNEL);
|
||
|
if (!saf775x) {
|
||
|
dev_err(&client->dev, "Can't allocate saf775x private struct\n");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
saf775x->control_data = client;
|
||
|
saf775x->controls = ctrls;
|
||
|
saf775x->num_controls = ARRAY_SIZE(ctrls);
|
||
|
|
||
|
mutex_init(&saf775x->mutex);
|
||
|
|
||
|
i2c_set_clientdata(client, saf775x);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int saf775x_i2c_remove(struct i2c_client *client)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct i2c_device_id saf775x_i2c_id[] = {
|
||
|
{
|
||
|
.name = "saf775x",
|
||
|
.driver_data = 0,
|
||
|
},
|
||
|
{ },
|
||
|
};
|
||
|
MODULE_DEVICE_TABLE(i2c, saf775x_i2c_id);
|
||
|
|
||
|
static struct i2c_driver saf775x_i2c_driver = {
|
||
|
.driver = {
|
||
|
.name = DRV_NAME,
|
||
|
.owner = THIS_MODULE,
|
||
|
},
|
||
|
.probe = saf775x_i2c_probe,
|
||
|
.remove = saf775x_i2c_remove,
|
||
|
.id_table = saf775x_i2c_id,
|
||
|
};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#if defined(CONFIG_SPI_MASTER)
|
||
|
static int saf775x_spi_probe(struct spi_device *spi)
|
||
|
{
|
||
|
struct saf775x_priv *saf775x;
|
||
|
struct saf775x_device_interfaces *devifs = saf775x_get_devifs();
|
||
|
|
||
|
devifs->spi = spi;
|
||
|
|
||
|
saf775x = devm_kzalloc(&spi->dev, sizeof(struct saf775x_priv),
|
||
|
GFP_KERNEL);
|
||
|
if (!saf775x) {
|
||
|
dev_err(&spi->dev, "Can't allocate saf775x private struct\n");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
saf775x->control_data = spi;
|
||
|
saf775x->controls = ctrls;
|
||
|
saf775x->num_controls = ARRAY_SIZE(ctrls);
|
||
|
|
||
|
mutex_init(&saf775x->mutex);
|
||
|
|
||
|
spi_set_drvdata(spi, saf775x);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int saf775x_spi_remove(struct spi_device *spi)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static struct spi_driver saf775x_spi_driver = {
|
||
|
.driver = {
|
||
|
.name = DRV_NAME,
|
||
|
.owner = THIS_MODULE,
|
||
|
},
|
||
|
.probe = saf775x_spi_probe,
|
||
|
.remove = saf775x_spi_remove,
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
static int saf775x_probe(struct platform_device *pdev)
|
||
|
{
|
||
|
|
||
|
struct saf775x_ioctl_ops *saf775x_ops;
|
||
|
int ret = 0;
|
||
|
|
||
|
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||
|
ret = i2c_add_driver(&saf775x_i2c_driver);
|
||
|
if (ret != 0)
|
||
|
return ret;
|
||
|
#endif
|
||
|
#if defined(CONFIG_SPI_MASTER)
|
||
|
ret = spi_register_driver(&saf775x_spi_driver);
|
||
|
if (ret != 0)
|
||
|
return ret;
|
||
|
#endif
|
||
|
|
||
|
saf775x_hwdep_create();
|
||
|
|
||
|
saf775x_ops = saf775x_get_ioctl_ops();
|
||
|
saf775x_ops->codec_write = saf775x_soc_write;
|
||
|
saf775x_ops->codec_reset = saf775x_chip_reset;
|
||
|
saf775x_ops->codec_read = saf775x_soc_read;
|
||
|
saf775x_ops->codec_set_ctrl = saf775x_soc_set_ctrl;
|
||
|
saf775x_ops->codec_get_ctrl = saf775x_soc_get_ctrl;
|
||
|
saf775x_ops->codec_write_keycode = saf775x_soc_write_keycode;
|
||
|
#if defined(CONFIG_SPI_MASTER)
|
||
|
saf775x_ops->codec_flash = saf775x_soc_flash_image;
|
||
|
saf775x_ops->codec_read_status = saf775x_soc_read_status;
|
||
|
#endif
|
||
|
#if defined(TEGRA_GPIO_D3_RESET)
|
||
|
saf775x_chip_get_rst_gpio();
|
||
|
#endif
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int saf775x_remove(struct platform_device *pdev)
|
||
|
{
|
||
|
saf775x_hwdep_cleanup();
|
||
|
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||
|
i2c_del_driver(&saf775x_i2c_driver);
|
||
|
#endif
|
||
|
#if defined(CONFIG_SPI_MASTER)
|
||
|
spi_unregister_driver(&saf775x_spi_driver);
|
||
|
#endif
|
||
|
#if defined(TEGRA_GPIO_D3_RESET)
|
||
|
gpio_free(tmpm32x_rst_gpio);
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct of_device_id saf775x_of_match[] = {
|
||
|
{ .compatible = "nvidia,tegra-saf775x", .data = NULL, },
|
||
|
{},
|
||
|
};
|
||
|
|
||
|
static struct platform_driver saf775x_driver = {
|
||
|
.driver = {
|
||
|
.name = "saf775x",
|
||
|
.owner = THIS_MODULE,
|
||
|
.of_match_table = of_match_ptr(saf775x_of_match),
|
||
|
},
|
||
|
.probe = saf775x_probe,
|
||
|
.remove = saf775x_remove,
|
||
|
};
|
||
|
|
||
|
static int __init saf775x_modinit(void)
|
||
|
{
|
||
|
return platform_driver_register(&saf775x_driver);
|
||
|
}
|
||
|
module_init(saf775x_modinit);
|
||
|
|
||
|
static void __exit saf775x_modexit(void)
|
||
|
{
|
||
|
platform_driver_unregister(&saf775x_driver);
|
||
|
}
|
||
|
module_exit(saf775x_modexit);
|
||
|
|
||
|
MODULE_AUTHOR("Arun S L <aruns@nvidia.com>");
|
||
|
MODULE_DESCRIPTION("SAF775X Soc Audio driver");
|
||
|
MODULE_LICENSE("GPL");
|