727 lines
19 KiB
C
727 lines
19 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* maxim-max96789.c -- I2C register interface access for max96789 serdes chip
|
|
*
|
|
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
|
|
*
|
|
* Author: luowei <lw@rock-chips.com>
|
|
*/
|
|
|
|
#include "../core.h"
|
|
#include "maxim-max96789.h"
|
|
|
|
struct serdes_function_data {
|
|
u8 gpio_out_dis:1;
|
|
u8 gpio_tx_en:1;
|
|
u8 gpio_rx_en:1;
|
|
u8 gpio_tx_id;
|
|
u8 gpio_rx_id;
|
|
u16 mdelay;
|
|
};
|
|
|
|
struct config_desc {
|
|
u16 reg;
|
|
u8 mask;
|
|
u8 val;
|
|
};
|
|
|
|
struct serdes_group_data {
|
|
const struct config_desc *configs;
|
|
int num_configs;
|
|
};
|
|
|
|
static int MAX96789_MFP0_pins[] = {0};
|
|
static int MAX96789_MFP1_pins[] = {1};
|
|
static int MAX96789_MFP2_pins[] = {2};
|
|
static int MAX96789_MFP3_pins[] = {3};
|
|
static int MAX96789_MFP4_pins[] = {4};
|
|
static int MAX96789_MFP5_pins[] = {5};
|
|
static int MAX96789_MFP6_pins[] = {6};
|
|
static int MAX96789_MFP7_pins[] = {7};
|
|
|
|
static int MAX96789_MFP8_pins[] = {8};
|
|
static int MAX96789_MFP9_pins[] = {9};
|
|
static int MAX96789_MFP10_pins[] = {10};
|
|
static int MAX96789_MFP11_pins[] = {11};
|
|
static int MAX96789_MFP12_pins[] = {12};
|
|
static int MAX96789_MFP13_pins[] = {13};
|
|
static int MAX96789_MFP14_pins[] = {14};
|
|
static int MAX96789_MFP15_pins[] = {15};
|
|
|
|
static int MAX96789_MFP16_pins[] = {16};
|
|
static int MAX96789_MFP17_pins[] = {17};
|
|
static int MAX96789_MFP18_pins[] = {18};
|
|
static int MAX96789_MFP19_pins[] = {19};
|
|
static int MAX96789_MFP20_pins[] = {20};
|
|
static int MAX96789_I2C_pins[] = {19, 20};
|
|
static int MAX96789_UART_pins[] = {19, 20};
|
|
|
|
#define GROUP_DESC(nm) \
|
|
{ \
|
|
.name = #nm, \
|
|
.pins = nm ## _pins, \
|
|
.num_pins = ARRAY_SIZE(nm ## _pins), \
|
|
}
|
|
|
|
#define GROUP_DESC_CONFIG(nm) \
|
|
{ \
|
|
.name = #nm, \
|
|
.pins = nm ## _pins, \
|
|
.num_pins = ARRAY_SIZE(nm ## _pins), \
|
|
.data = (void *)(const struct serdes_group_data []) { \
|
|
{ \
|
|
.configs = nm ## _configs, \
|
|
.num_configs = ARRAY_SIZE(nm ## _configs), \
|
|
} \
|
|
}, \
|
|
}
|
|
|
|
static const struct config_desc MAX96789_MFP0_configs[] = {
|
|
{ 0x0005, LOCK_EN, 0 },
|
|
{ 0x0048, LOC_MS_EN, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP1_configs[] = {
|
|
{ 0x0005, ERRB_EN, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP4_configs[] = {
|
|
{ 0x070, SPI_EN, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP5_configs[] = {
|
|
{ 0x006, RCLKEN, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP7_configs[] = {
|
|
{ 0x0002, AUD_TX_EN_X, 0 },
|
|
{ 0x0002, AUD_TX_EN_Y, 0 }
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP8_configs[] = {
|
|
{ 0x0002, AUD_TX_EN_X, 0 },
|
|
{ 0x0002, AUD_TX_EN_Y, 0 }
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP9_configs[] = {
|
|
{ 0x0002, AUD_TX_EN_X, 0 },
|
|
{ 0x0002, AUD_TX_EN_Y, 0 }
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP10_configs[] = {
|
|
{ 0x0001, IIC_2_EN, 0 },
|
|
{ 0x0003, UART_2_EN, 0 },
|
|
{ 0x0140, AUD_RX_EN, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP11_configs[] = {
|
|
{ 0x0001, IIC_2_EN, 0 },
|
|
{ 0x0003, UART_2_EN, 0 },
|
|
{ 0x0140, AUD_RX_EN, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP12_configs[] = {
|
|
{ 0x0140, AUD_RX_EN, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP13_configs[] = {
|
|
{ 0x0005, PU_LF0, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP14_configs[] = {
|
|
{ 0x0005, PU_LF1, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP15_configs[] = {
|
|
{ 0x0005, PU_LF2, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP16_configs[] = {
|
|
{ 0x0005, PU_LF3, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP17_configs[] = {
|
|
{ 0x0001, IIC_1_EN, 0 },
|
|
{ 0x0003, UART_1_EN, 0 },
|
|
};
|
|
|
|
static const struct config_desc MAX96789_MFP18_configs[] = {
|
|
{ 0x0001, IIC_1_EN, 0 },
|
|
{ 0x0003, UART_1_EN, 0 },
|
|
};
|
|
|
|
static const char *serdes_gpio_groups[] = {
|
|
"MAX96789_MFP0", "MAX96789_MFP1", "MAX96789_MFP2", "MAX96789_MFP3",
|
|
"MAX96789_MFP4", "MAX96789_MFP5", "MAX96789_MFP6", "MAX96789_MFP7",
|
|
|
|
"MAX96789_MFP8", "MAX96789_MFP9", "MAX96789_MFP10", "MAX96789_MFP11",
|
|
"MAX96789_MFP12", "MAX96789_MFP13", "MAX96789_MFP14", "MAX96789_MFP15",
|
|
|
|
"MAX96789_MFP16", "MAX96789_MFP17", "MAX96789_MFP18", "MAX96789_MFP19",
|
|
"MAX96789_MFP20",
|
|
};
|
|
|
|
static const char *MAX96789_I2C_groups[] = { "MAX96789_I2C" };
|
|
static const char *MAX96789_UART_groups[] = { "MAX96789_UART" };
|
|
|
|
#define FUNCTION_DESC(nm) \
|
|
{ \
|
|
.name = #nm, \
|
|
.group_names = nm##_groups, \
|
|
.num_group_names = ARRAY_SIZE(nm##_groups), \
|
|
} \
|
|
|
|
#define FUNCTION_DESC_GPIO_INPUT(id) \
|
|
{ \
|
|
.name = "DES_RXID"#id"_TO_SER", \
|
|
.group_names = serdes_gpio_groups, \
|
|
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
|
|
.data = (void *)(const struct serdes_function_data []) { \
|
|
{ .gpio_out_dis = 0, .gpio_rx_en = 1, .gpio_rx_id = id } \
|
|
}, \
|
|
} \
|
|
|
|
#define FUNCTION_DESC_GPIO_OUTPUT(id) \
|
|
{ \
|
|
.name = "SER_TXID"#id"_TO_DES", \
|
|
.group_names = serdes_gpio_groups, \
|
|
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
|
|
.data = (void *)(const struct serdes_function_data []) { \
|
|
{ .gpio_out_dis = 1, .gpio_tx_en = 1, .gpio_tx_id = id } \
|
|
}, \
|
|
} \
|
|
|
|
static struct pinctrl_pin_desc max96789_pins_desc[] = {
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP0, "MAX96789_MFP0"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP1, "MAX96789_MFP1"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP2, "MAX96789_MFP2"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP3, "MAX96789_MFP3"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP4, "MAX96789_MFP4"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP5, "MAX96789_MFP5"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP6, "MAX96789_MFP6"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP7, "MAX96789_MFP7"),
|
|
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP8, "MAX96789_MFP8"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP9, "MAX96789_MFP9"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP10, "MAX96789_MFP10"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP11, "MAX96789_MFP11"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP12, "MAX96789_MFP12"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP13, "MAX96789_MFP13"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP14, "MAX96789_MFP14"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP15, "MAX96789_MFP15"),
|
|
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP16, "MAX96789_MFP16"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP17, "MAX96789_MFP17"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP18, "MAX96789_MFP18"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP19, "MAX96789_MFP19"),
|
|
PINCTRL_PIN(MAXIM_MAX96789_MFP20, "MAX96789_MFP20"),
|
|
};
|
|
|
|
static struct group_desc max96789_groups_desc[] = {
|
|
GROUP_DESC_CONFIG(MAX96789_MFP0),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP1),
|
|
GROUP_DESC(MAX96789_MFP2),
|
|
GROUP_DESC(MAX96789_MFP3),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP4),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP5),
|
|
GROUP_DESC(MAX96789_MFP6),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP7),
|
|
|
|
GROUP_DESC_CONFIG(MAX96789_MFP8),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP9),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP10),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP11),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP12),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP13),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP14),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP15),
|
|
|
|
GROUP_DESC_CONFIG(MAX96789_MFP16),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP17),
|
|
GROUP_DESC_CONFIG(MAX96789_MFP18),
|
|
GROUP_DESC(MAX96789_MFP19),
|
|
GROUP_DESC(MAX96789_MFP20),
|
|
GROUP_DESC(MAX96789_I2C),
|
|
GROUP_DESC(MAX96789_UART),
|
|
};
|
|
|
|
static struct function_desc max96789_functions_desc[] = {
|
|
FUNCTION_DESC_GPIO_INPUT(0),
|
|
FUNCTION_DESC_GPIO_INPUT(1),
|
|
FUNCTION_DESC_GPIO_INPUT(2),
|
|
FUNCTION_DESC_GPIO_INPUT(3),
|
|
FUNCTION_DESC_GPIO_INPUT(4),
|
|
FUNCTION_DESC_GPIO_INPUT(5),
|
|
FUNCTION_DESC_GPIO_INPUT(6),
|
|
FUNCTION_DESC_GPIO_INPUT(7),
|
|
|
|
FUNCTION_DESC_GPIO_INPUT(8),
|
|
FUNCTION_DESC_GPIO_INPUT(9),
|
|
FUNCTION_DESC_GPIO_INPUT(10),
|
|
FUNCTION_DESC_GPIO_INPUT(11),
|
|
FUNCTION_DESC_GPIO_INPUT(12),
|
|
FUNCTION_DESC_GPIO_INPUT(13),
|
|
FUNCTION_DESC_GPIO_INPUT(14),
|
|
FUNCTION_DESC_GPIO_INPUT(15),
|
|
|
|
FUNCTION_DESC_GPIO_INPUT(16),
|
|
FUNCTION_DESC_GPIO_INPUT(17),
|
|
FUNCTION_DESC_GPIO_INPUT(18),
|
|
FUNCTION_DESC_GPIO_INPUT(19),
|
|
FUNCTION_DESC_GPIO_INPUT(20),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT(0),
|
|
FUNCTION_DESC_GPIO_OUTPUT(1),
|
|
FUNCTION_DESC_GPIO_OUTPUT(2),
|
|
FUNCTION_DESC_GPIO_OUTPUT(3),
|
|
FUNCTION_DESC_GPIO_OUTPUT(4),
|
|
FUNCTION_DESC_GPIO_OUTPUT(5),
|
|
FUNCTION_DESC_GPIO_OUTPUT(6),
|
|
FUNCTION_DESC_GPIO_OUTPUT(7),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT(8),
|
|
FUNCTION_DESC_GPIO_OUTPUT(9),
|
|
FUNCTION_DESC_GPIO_OUTPUT(10),
|
|
FUNCTION_DESC_GPIO_OUTPUT(11),
|
|
FUNCTION_DESC_GPIO_OUTPUT(12),
|
|
FUNCTION_DESC_GPIO_OUTPUT(13),
|
|
FUNCTION_DESC_GPIO_OUTPUT(14),
|
|
FUNCTION_DESC_GPIO_OUTPUT(15),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT(16),
|
|
FUNCTION_DESC_GPIO_OUTPUT(17),
|
|
FUNCTION_DESC_GPIO_OUTPUT(18),
|
|
FUNCTION_DESC_GPIO_OUTPUT(19),
|
|
FUNCTION_DESC_GPIO_OUTPUT(20),
|
|
|
|
FUNCTION_DESC(MAX96789_I2C),
|
|
FUNCTION_DESC(MAX96789_UART),
|
|
};
|
|
|
|
static struct serdes_chip_pinctrl_info max96789_pinctrl_info = {
|
|
.pins = max96789_pins_desc,
|
|
.num_pins = ARRAY_SIZE(max96789_pins_desc),
|
|
.groups = max96789_groups_desc,
|
|
.num_groups = ARRAY_SIZE(max96789_groups_desc),
|
|
.functions = max96789_functions_desc,
|
|
.num_functions = ARRAY_SIZE(max96789_functions_desc),
|
|
};
|
|
|
|
static bool max96789_bridge_link_locked(struct serdes *serdes)
|
|
{
|
|
u32 val;
|
|
|
|
if (dm_gpio_is_valid(&serdes->lock_gpio)) {
|
|
val = dm_gpio_get_value(&serdes->lock_gpio);
|
|
SERDES_DBG_CHIP("serdes %s:val=%d\n", __func__, val);
|
|
return val;
|
|
}
|
|
|
|
if (serdes_reg_read(serdes, 0x0013, &val)) {
|
|
SERDES_DBG_CHIP("serdes %s: false val=%d\n", __func__, val);
|
|
return false;
|
|
}
|
|
|
|
if (!FIELD_GET(LOCKED, val)) {
|
|
SERDES_DBG_CHIP("serdes %s: false val=%d\n", __func__, val);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool max96789_bridge_detect(struct serdes *serdes)
|
|
{
|
|
return max96789_bridge_link_locked(serdes);
|
|
}
|
|
|
|
static int max96789_bridge_enable(struct serdes *serdes)
|
|
{
|
|
int ret = 0;
|
|
|
|
SERDES_DBG_CHIP("%s: serdes chip %s ret=%d\n",
|
|
__func__, serdes->chip_data->name, ret);
|
|
return ret;
|
|
}
|
|
|
|
static int max96789_bridge_disable(struct serdes *serdes)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = serdes_set_bits(serdes, 0x0002, VID_TX_EN_X,
|
|
FIELD_PREP(VID_TX_EN_X, 0));
|
|
|
|
return ret;
|
|
}
|
|
|
|
static struct serdes_chip_bridge_ops max96789_bridge_ops = {
|
|
.detect = max96789_bridge_detect,
|
|
.enable = max96789_bridge_enable,
|
|
.disable = max96789_bridge_disable,
|
|
};
|
|
|
|
static int max96789_pinctrl_set_pin_mux(struct serdes *serdes,
|
|
unsigned int pin_selector,
|
|
unsigned int func_selector)
|
|
{
|
|
struct function_desc *func;
|
|
struct pinctrl_pin_desc *pin;
|
|
int offset;
|
|
u16 ms;
|
|
|
|
func = &serdes->chip_data->pinctrl_info->functions[func_selector];
|
|
if (!func) {
|
|
printf("%s: func is null\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pin = &serdes->chip_data->pinctrl_info->pins[pin_selector];
|
|
if (!pin) {
|
|
printf("%s: pin is null\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p pin=%s num=%d\n",
|
|
__func__, serdes->dev->name,
|
|
func->name, func->data,
|
|
pin->name, pin->number);
|
|
|
|
if (func->data) {
|
|
struct serdes_function_data *fdata = func->data;
|
|
|
|
ms = fdata->mdelay;
|
|
offset = pin->number;
|
|
if (offset > 32)
|
|
dev_err(serdes->dev, "%s offset=%d > 32\n",
|
|
serdes->dev->name, offset);
|
|
else
|
|
SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
|
|
__func__, serdes->dev->name,
|
|
fdata->gpio_tx_id, fdata->gpio_rx_id, offset);
|
|
|
|
if (!ms) {
|
|
serdes_set_bits(serdes, GPIO_A_REG(offset),
|
|
GPIO_OUT_DIS | GPIO_RX_EN | GPIO_TX_EN,
|
|
FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis) |
|
|
FIELD_PREP(GPIO_RX_EN, fdata->gpio_rx_en) |
|
|
FIELD_PREP(GPIO_TX_EN, fdata->gpio_tx_en));
|
|
|
|
if (fdata->gpio_tx_en)
|
|
serdes_set_bits(serdes,
|
|
GPIO_B_REG(offset),
|
|
GPIO_TX_ID,
|
|
FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
|
|
if (fdata->gpio_rx_en)
|
|
serdes_set_bits(serdes,
|
|
GPIO_C_REG(offset),
|
|
GPIO_RX_ID,
|
|
FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
|
|
} else {
|
|
mdelay(ms);
|
|
SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max96789_pinctrl_set_grp_mux(struct serdes *serdes,
|
|
unsigned int group_selector,
|
|
unsigned int func_selector)
|
|
{
|
|
struct serdes_pinctrl *pinctrl = serdes->serdes_pinctrl;
|
|
struct function_desc *func;
|
|
struct group_desc *grp;
|
|
int i, offset;
|
|
u16 ms;
|
|
|
|
func = &serdes->chip_data->pinctrl_info->functions[func_selector];
|
|
if (!func) {
|
|
printf("%s: func is null\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
grp = &serdes->chip_data->pinctrl_info->groups[group_selector];
|
|
if (!grp) {
|
|
printf("%s: grp is null\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SERDES_DBG_CHIP("%s: serdes %s func=%s data=%p grp=%s data=%p num=%d\n",
|
|
__func__, serdes->chip_data->name, func->name,
|
|
func->data, grp->name, grp->data, grp->num_pins);
|
|
|
|
if (func->data) {
|
|
struct serdes_function_data *fdata = func->data;
|
|
|
|
ms = fdata->mdelay;
|
|
for (i = 0; i < grp->num_pins; i++) {
|
|
offset = grp->pins[i] - pinctrl->pin_base;
|
|
if (offset > 32)
|
|
dev_err(serdes->dev, "%s offset=%d > 32\n",
|
|
serdes->dev->name, offset);
|
|
else
|
|
SERDES_DBG_CHIP("%s: serdes %s txid=%d rxid=%d off=%d\n",
|
|
__func__, serdes->dev->name,
|
|
fdata->gpio_tx_id, fdata->gpio_rx_id, offset);
|
|
|
|
if (!ms) {
|
|
serdes_set_bits(serdes, GPIO_A_REG(offset),
|
|
GPIO_OUT_DIS | GPIO_RX_EN | GPIO_TX_EN,
|
|
FIELD_PREP(GPIO_OUT_DIS, fdata->gpio_out_dis) |
|
|
FIELD_PREP(GPIO_RX_EN, fdata->gpio_rx_en) |
|
|
FIELD_PREP(GPIO_TX_EN, fdata->gpio_tx_en));
|
|
if (fdata->gpio_tx_en)
|
|
serdes_set_bits(serdes,
|
|
GPIO_B_REG(offset),
|
|
GPIO_TX_ID,
|
|
FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
|
|
if (fdata->gpio_rx_en)
|
|
serdes_set_bits(serdes,
|
|
GPIO_C_REG(offset),
|
|
GPIO_RX_ID,
|
|
FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
|
|
} else {
|
|
mdelay(ms);
|
|
SERDES_DBG_CHIP("%s: delay %dms\n", __func__, ms);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (grp->data) {
|
|
struct serdes_group_data *gdata = grp->data;
|
|
|
|
for (i = 0; i < gdata->num_configs; i++) {
|
|
const struct config_desc *config = &gdata->configs[i];
|
|
|
|
serdes_set_bits(serdes, config->reg,
|
|
config->mask, config->val);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max96789_pinctrl_config_set(struct serdes *serdes,
|
|
unsigned int pin_selector,
|
|
unsigned int param,
|
|
unsigned int argument)
|
|
{
|
|
u8 res_cfg;
|
|
|
|
switch (param) {
|
|
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
|
serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
|
|
OUT_TYPE, FIELD_PREP(OUT_TYPE, 0));
|
|
break;
|
|
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
|
serdes_set_bits(serdes, GPIO_B_REG(pin_selector),
|
|
OUT_TYPE, FIELD_PREP(OUT_TYPE, 1));
|
|
break;
|
|
case PIN_CONFIG_BIAS_DISABLE:
|
|
serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
|
|
PULL_UPDN_SEL,
|
|
FIELD_PREP(PULL_UPDN_SEL, 0));
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_UP:
|
|
switch (argument) {
|
|
case 40000:
|
|
res_cfg = 0;
|
|
break;
|
|
case 1000000:
|
|
res_cfg = 1;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
|
|
RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
|
|
serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
|
|
PULL_UPDN_SEL,
|
|
FIELD_PREP(PULL_UPDN_SEL, 1));
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
switch (argument) {
|
|
case 40000:
|
|
res_cfg = 0;
|
|
break;
|
|
case 1000000:
|
|
res_cfg = 1;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
|
|
RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
|
|
serdes_set_bits(serdes, GPIO_C_REG(pin_selector),
|
|
PULL_UPDN_SEL,
|
|
FIELD_PREP(PULL_UPDN_SEL, 2));
|
|
break;
|
|
case PIN_CONFIG_OUTPUT:
|
|
serdes_set_bits(serdes, GPIO_A_REG(pin_selector),
|
|
GPIO_OUT_DIS | GPIO_OUT,
|
|
FIELD_PREP(GPIO_OUT_DIS, 0) |
|
|
FIELD_PREP(GPIO_OUT, argument));
|
|
break;
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct serdes_chip_pinctrl_ops max96789_pinctrl_ops = {
|
|
.pinconf_set = max96789_pinctrl_config_set,
|
|
.pinmux_set = max96789_pinctrl_set_pin_mux,
|
|
.pinmux_group_set = max96789_pinctrl_set_grp_mux,
|
|
};
|
|
|
|
static int max96789_gpio_direction_input(struct serdes *serdes, int gpio)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96789_gpio_direction_output(struct serdes *serdes,
|
|
int gpio, int value)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96789_gpio_get_level(struct serdes *serdes, int gpio)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96789_gpio_set_level(struct serdes *serdes, int gpio, int value)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96789_gpio_set_config(struct serdes *serdes,
|
|
int gpio, unsigned long config)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96789_gpio_to_irq(struct serdes *serdes, int gpio)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static struct serdes_chip_gpio_ops max96789_gpio_ops = {
|
|
.direction_input = max96789_gpio_direction_input,
|
|
.direction_output = max96789_gpio_direction_output,
|
|
.get_level = max96789_gpio_get_level,
|
|
.set_level = max96789_gpio_set_level,
|
|
.set_config = max96789_gpio_set_config,
|
|
.to_irq = max96789_gpio_to_irq,
|
|
};
|
|
|
|
static int max96789_select(struct serdes *serdes, int chan)
|
|
{
|
|
u32 link_cfg, link_status;
|
|
int ret = 0;
|
|
int i = 0;
|
|
|
|
serdes_set_bits(serdes, 0x0001, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 0));
|
|
|
|
serdes_reg_read(serdes, 0x0010, &link_cfg);
|
|
if ((link_cfg & LINK_CFG) == SPLITTER_MODE)
|
|
SERDES_DBG_CHIP("%s: serdes %s is split mode cfg=0x%x\n",
|
|
__func__,
|
|
serdes->chip_data->name, link_cfg);
|
|
|
|
if (chan == 0 && (link_cfg & LINK_CFG) != DUAL_LINK) {
|
|
ret = serdes_set_bits(serdes, 0x0004,
|
|
LINK_EN_B | LINK_EN_A,
|
|
FIELD_PREP(LINK_EN_A, 1) |
|
|
FIELD_PREP(LINK_EN_B, 1));
|
|
ret = serdes_set_bits(serdes, 0x0010,
|
|
RESET_ONESHOT | AUTO_LINK | LINK_CFG,
|
|
FIELD_PREP(RESET_ONESHOT, 1) |
|
|
FIELD_PREP(AUTO_LINK, 0) |
|
|
FIELD_PREP(LINK_CFG, DUAL_LINK));
|
|
SERDES_DBG_CHIP("%s: change to use dual link\n", __func__);
|
|
} else if (chan == 1 && (link_cfg & LINK_CFG) != LINKA) {
|
|
ret = serdes_set_bits(serdes, 0x0004,
|
|
LINK_EN_B | LINK_EN_A,
|
|
FIELD_PREP(LINK_EN_A, 1) |
|
|
FIELD_PREP(LINK_EN_B, 0));
|
|
ret = serdes_set_bits(serdes, 0x0010,
|
|
RESET_ONESHOT | AUTO_LINK | LINK_CFG,
|
|
FIELD_PREP(RESET_ONESHOT, 1) |
|
|
FIELD_PREP(AUTO_LINK, 0) |
|
|
FIELD_PREP(LINK_CFG, LINKA));
|
|
SERDES_DBG_CHIP("%s: change to use linkA\n", __func__);
|
|
} else if (chan == 2 && (link_cfg & LINK_CFG) != LINKB) {
|
|
ret = serdes_set_bits(serdes, 0x0004,
|
|
LINK_EN_B | LINK_EN_A,
|
|
FIELD_PREP(LINK_EN_A, 0) |
|
|
FIELD_PREP(LINK_EN_B, 1));
|
|
ret = serdes_set_bits(serdes, 0x0010,
|
|
RESET_ONESHOT | AUTO_LINK | LINK_CFG,
|
|
FIELD_PREP(RESET_ONESHOT, 1) |
|
|
FIELD_PREP(AUTO_LINK, 0) |
|
|
FIELD_PREP(LINK_CFG, LINKB));
|
|
SERDES_DBG_CHIP("%s: change to use linkB\n", __func__);
|
|
} else if (chan == 3 && (link_cfg & LINK_CFG) != SPLITTER_MODE) {
|
|
ret = serdes_set_bits(serdes, 0x0004,
|
|
LINK_EN_B | LINK_EN_A,
|
|
FIELD_PREP(LINK_EN_A, 1) |
|
|
FIELD_PREP(LINK_EN_B, 1));
|
|
ret = serdes_set_bits(serdes, 0x0010,
|
|
RESET_ONESHOT | AUTO_LINK | LINK_CFG,
|
|
FIELD_PREP(RESET_ONESHOT, 1) |
|
|
FIELD_PREP(AUTO_LINK, 0) |
|
|
FIELD_PREP(LINK_CFG, SPLITTER_MODE));
|
|
SERDES_DBG_CHIP("%s: change to use split mode\n", __func__);
|
|
}
|
|
|
|
for (i = 0; i < 20; i++) {
|
|
serdes_reg_read(serdes, 0x0013, &link_status);
|
|
if (link_status & LOCKED)
|
|
break;
|
|
mdelay(5);
|
|
}
|
|
|
|
if (i > 9)
|
|
printf("%s: %s GMSL2 link lock timeout\n", __func__,
|
|
serdes->dev->name);
|
|
else
|
|
printf("%s: %s GMSL2 link locked\n", __func__,
|
|
serdes->dev->name);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int max96789_deselect(struct serdes *serdes, int chan)
|
|
{
|
|
//serdes_set_bits(serdes, 0x0001, DIS_REM_CC,
|
|
// FIELD_PREP(DIS_REM_CC, 1));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct serdes_chip_split_ops max96789_split_ops = {
|
|
.select = max96789_select,
|
|
.deselect = max96789_deselect,
|
|
};
|
|
|
|
struct serdes_chip_data serdes_max96789_data = {
|
|
.name = "max96789",
|
|
.serdes_type = TYPE_SER,
|
|
.serdes_id = MAXIM_ID_MAX96789,
|
|
.connector_type = DRM_MODE_CONNECTOR_DSI,
|
|
.pinctrl_info = &max96789_pinctrl_info,
|
|
.bridge_ops = &max96789_bridge_ops,
|
|
.pinctrl_ops = &max96789_pinctrl_ops,
|
|
.gpio_ops = &max96789_gpio_ops,
|
|
.split_ops = &max96789_split_ops,
|
|
};
|
|
EXPORT_SYMBOL_GPL(serdes_max96789_data);
|
|
|
|
MODULE_LICENSE("GPL");
|