950 lines
25 KiB
C
950 lines
25 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* maxim-max96745.c -- I2C register interface access for max96745 serdes chip
|
|
*
|
|
* Copyright (c) 2023-2028 Rockchip Electronics Co., Ltd.
|
|
*
|
|
* Author:
|
|
*/
|
|
|
|
#include "../core.h"
|
|
#include "maxim-max96745.h"
|
|
|
|
static bool max96745_volatile_reg(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case 0x0076:
|
|
case 0x0086:
|
|
case 0x0100:
|
|
case 0x0200 ... 0x02ce:
|
|
case 0x7000:
|
|
case 0x7070:
|
|
case 0x7074:
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static struct regmap_config max96745_regmap_config = {
|
|
.name = "max96745",
|
|
.reg_bits = 16,
|
|
.val_bits = 8,
|
|
.max_register = 0x8000,
|
|
.volatile_reg = max96745_volatile_reg,
|
|
.cache_type = REGCACHE_RBTREE,
|
|
};
|
|
|
|
struct serdes_function_data {
|
|
u8 gpio_out_dis:1;
|
|
u8 gpio_io_rx_en:1;
|
|
u8 gpio_tx_en_a:1;
|
|
u8 gpio_tx_en_b:1;
|
|
u8 gpio_rx_en_a:1;
|
|
u8 gpio_rx_en_b:1;
|
|
u8 gpio_tx_id;
|
|
u8 gpio_rx_id;
|
|
};
|
|
|
|
struct config_desc {
|
|
u16 reg;
|
|
u8 mask;
|
|
u8 val;
|
|
};
|
|
|
|
struct serdes_group_data {
|
|
const struct config_desc *configs;
|
|
int num_configs;
|
|
};
|
|
|
|
static int MAX96745_MFP0_pins[] = {0};
|
|
static int MAX96745_MFP1_pins[] = {1};
|
|
static int MAX96745_MFP2_pins[] = {2};
|
|
static int MAX96745_MFP3_pins[] = {3};
|
|
static int MAX96745_MFP4_pins[] = {4};
|
|
static int MAX96745_MFP5_pins[] = {5};
|
|
static int MAX96745_MFP6_pins[] = {6};
|
|
static int MAX96745_MFP7_pins[] = {7};
|
|
|
|
static int MAX96745_MFP8_pins[] = {8};
|
|
static int MAX96745_MFP9_pins[] = {9};
|
|
static int MAX96745_MFP10_pins[] = {10};
|
|
static int MAX96745_MFP11_pins[] = {11};
|
|
static int MAX96745_MFP12_pins[] = {12};
|
|
static int MAX96745_MFP13_pins[] = {13};
|
|
static int MAX96745_MFP14_pins[] = {14};
|
|
static int MAX96745_MFP15_pins[] = {15};
|
|
|
|
static int MAX96745_MFP16_pins[] = {16};
|
|
static int MAX96745_MFP17_pins[] = {17};
|
|
static int MAX96745_MFP18_pins[] = {18};
|
|
static int MAX96745_MFP19_pins[] = {19};
|
|
static int MAX96745_MFP20_pins[] = {20};
|
|
static int MAX96745_MFP21_pins[] = {21};
|
|
static int MAX96745_MFP22_pins[] = {22};
|
|
static int MAX96745_MFP23_pins[] = {23};
|
|
|
|
static int MAX96745_MFP24_pins[] = {24};
|
|
static int MAX96745_MFP25_pins[] = {25};
|
|
static int MAX96745_I2C_pins[] = {3, 7};
|
|
static int MAX96745_UART_pins[] = {3, 7};
|
|
|
|
#define GROUP_DESC(nm) \
|
|
{ \
|
|
.name = #nm, \
|
|
.pins = nm ## _pins, \
|
|
.num_pins = ARRAY_SIZE(nm ## _pins), \
|
|
}
|
|
|
|
static const char *serdes_gpio_groups[] = {
|
|
"MAX96745_MFP0", "MAX96745_MFP1", "MAX96745_MFP2", "MAX96745_MFP3",
|
|
"MAX96745_MFP4", "MAX96745_MFP5", "MAX96745_MFP6", "MAX96745_MFP7",
|
|
|
|
"MAX96745_MFP8", "MAX96745_MFP9", "MAX96745_MFP10", "MAX96745_MFP11",
|
|
"MAX96745_MFP12", "MAX96745_MFP13", "MAX96745_MFP14", "MAX96745_MFP15",
|
|
|
|
"MAX96745_MFP16", "MAX96745_MFP17", "MAX96745_MFP18", "MAX96745_MFP19",
|
|
"MAX96745_MFP20", "MAX96745_MFP21", "MAX96745_MFP22", "MAX96745_MFP23",
|
|
|
|
"MAX96745_MFP24", "MAX96745_MFP25",
|
|
};
|
|
|
|
static const char *MAX96745_I2C_groups[] = { "MAX96745_I2C" };
|
|
static const char *MAX96745_UART_groups[] = { "MAX96745_UART" };
|
|
|
|
#define FUNCTION_DESC(nm) \
|
|
{ \
|
|
.name = #nm, \
|
|
.group_names = nm##_groups, \
|
|
.num_group_names = ARRAY_SIZE(nm##_groups), \
|
|
} \
|
|
|
|
#define FUNCTION_DESC_GPIO_OUTPUT_A(id) \
|
|
{ \
|
|
.name = "SER_TXID"#id"_TO_DES_LINKA", \
|
|
.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_a = 1, \
|
|
.gpio_io_rx_en = 1, .gpio_tx_id = id } \
|
|
}, \
|
|
} \
|
|
|
|
#define FUNCTION_DESC_GPIO_OUTPUT_B(id) \
|
|
{ \
|
|
.name = "SER_TXID"#id"_TO_DES_LINKB", \
|
|
.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_b = 1, \
|
|
.gpio_io_rx_en = 1, .gpio_tx_id = id } \
|
|
}, \
|
|
} \
|
|
|
|
#define FUNCTION_DESC_GPIO_INPUT_A(id) \
|
|
{ \
|
|
.name = "DES_RXID"#id"_TO_SER_LINKA", \
|
|
.group_names = serdes_gpio_groups, \
|
|
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
|
|
.data = (void *)(const struct serdes_function_data []) { \
|
|
{ .gpio_rx_en_a = 1, .gpio_rx_id = id } \
|
|
}, \
|
|
} \
|
|
|
|
#define FUNCTION_DESC_GPIO_INPUT_B(id) \
|
|
{ \
|
|
.name = "DES_RXID"#id"_TO_SER_LINKB", \
|
|
.group_names = serdes_gpio_groups, \
|
|
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
|
|
.data = (void *)(const struct serdes_function_data []) { \
|
|
{ .gpio_rx_en_b = 1, .gpio_rx_id = id } \
|
|
}, \
|
|
} \
|
|
|
|
#define FUNCTION_DESC_GPIO() \
|
|
{ \
|
|
.name = "MAX96745_GPIO", \
|
|
.group_names = serdes_gpio_groups, \
|
|
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
|
|
.data = (void *)(const struct serdes_function_data []) { \
|
|
{ } \
|
|
}, \
|
|
} \
|
|
|
|
static struct pinctrl_pin_desc max96745_pins_desc[] = {
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP0, "MAX96745_MFP0"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP1, "MAX96745_MFP1"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP2, "MAX96745_MFP2"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP3, "MAX96745_MFP3"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP4, "MAX96745_MFP4"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP5, "MAX96745_MFP5"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP6, "MAX96745_MFP6"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP7, "MAX96745_MFP7"),
|
|
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP8, "MAX96745_MFP8"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP9, "MAX96745_MFP9"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP10, "MAX96745_MFP10"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP11, "MAX96745_MFP11"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP12, "MAX96745_MFP12"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP13, "MAX96745_MFP13"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP14, "MAX96745_MFP14"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP15, "MAX96745_MFP15"),
|
|
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP16, "MAX96745_MFP16"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP17, "MAX96745_MFP17"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP18, "MAX96745_MFP18"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP19, "MAX96745_MFP19"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP20, "MAX96745_MFP20"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP21, "MAX96745_MFP21"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP22, "MAX96745_MFP22"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP23, "MAX96745_MFP23"),
|
|
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP24, "MAX96745_MFP24"),
|
|
PINCTRL_PIN(MAXIM_MAX96745_MFP25, "MAX96745_MFP25"),
|
|
};
|
|
|
|
static struct group_desc max96745_groups_desc[] = {
|
|
GROUP_DESC(MAX96745_MFP0),
|
|
GROUP_DESC(MAX96745_MFP1),
|
|
GROUP_DESC(MAX96745_MFP2),
|
|
GROUP_DESC(MAX96745_MFP3),
|
|
GROUP_DESC(MAX96745_MFP4),
|
|
GROUP_DESC(MAX96745_MFP5),
|
|
GROUP_DESC(MAX96745_MFP6),
|
|
GROUP_DESC(MAX96745_MFP7),
|
|
|
|
GROUP_DESC(MAX96745_MFP8),
|
|
GROUP_DESC(MAX96745_MFP9),
|
|
GROUP_DESC(MAX96745_MFP10),
|
|
GROUP_DESC(MAX96745_MFP11),
|
|
GROUP_DESC(MAX96745_MFP12),
|
|
GROUP_DESC(MAX96745_MFP13),
|
|
GROUP_DESC(MAX96745_MFP14),
|
|
GROUP_DESC(MAX96745_MFP15),
|
|
|
|
GROUP_DESC(MAX96745_MFP16),
|
|
GROUP_DESC(MAX96745_MFP17),
|
|
GROUP_DESC(MAX96745_MFP18),
|
|
GROUP_DESC(MAX96745_MFP19),
|
|
GROUP_DESC(MAX96745_MFP20),
|
|
GROUP_DESC(MAX96745_MFP21),
|
|
GROUP_DESC(MAX96745_MFP22),
|
|
GROUP_DESC(MAX96745_MFP23),
|
|
|
|
GROUP_DESC(MAX96745_MFP24),
|
|
GROUP_DESC(MAX96745_MFP25),
|
|
|
|
GROUP_DESC(MAX96745_I2C),
|
|
GROUP_DESC(MAX96745_UART),
|
|
};
|
|
|
|
static struct function_desc max96745_functions_desc[] = {
|
|
FUNCTION_DESC_GPIO_INPUT_A(0),
|
|
FUNCTION_DESC_GPIO_INPUT_A(1),
|
|
FUNCTION_DESC_GPIO_INPUT_A(2),
|
|
FUNCTION_DESC_GPIO_INPUT_A(3),
|
|
FUNCTION_DESC_GPIO_INPUT_A(4),
|
|
FUNCTION_DESC_GPIO_INPUT_A(5),
|
|
FUNCTION_DESC_GPIO_INPUT_A(6),
|
|
FUNCTION_DESC_GPIO_INPUT_A(7),
|
|
|
|
FUNCTION_DESC_GPIO_INPUT_A(8),
|
|
FUNCTION_DESC_GPIO_INPUT_A(9),
|
|
FUNCTION_DESC_GPIO_INPUT_A(10),
|
|
FUNCTION_DESC_GPIO_INPUT_A(11),
|
|
FUNCTION_DESC_GPIO_INPUT_A(12),
|
|
FUNCTION_DESC_GPIO_INPUT_A(13),
|
|
FUNCTION_DESC_GPIO_INPUT_A(14),
|
|
FUNCTION_DESC_GPIO_INPUT_A(15),
|
|
|
|
FUNCTION_DESC_GPIO_INPUT_A(16),
|
|
FUNCTION_DESC_GPIO_INPUT_A(17),
|
|
FUNCTION_DESC_GPIO_INPUT_A(18),
|
|
FUNCTION_DESC_GPIO_INPUT_A(19),
|
|
FUNCTION_DESC_GPIO_INPUT_A(20),
|
|
FUNCTION_DESC_GPIO_INPUT_A(21),
|
|
FUNCTION_DESC_GPIO_INPUT_A(22),
|
|
FUNCTION_DESC_GPIO_INPUT_A(23),
|
|
|
|
FUNCTION_DESC_GPIO_INPUT_A(24),
|
|
FUNCTION_DESC_GPIO_INPUT_A(25),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(0),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(1),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(2),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(3),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(4),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(5),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(6),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(7),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(8),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(9),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(10),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(11),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(12),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(13),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(14),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(15),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(16),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(17),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(18),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(19),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(20),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(21),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(22),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(23),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(24),
|
|
FUNCTION_DESC_GPIO_OUTPUT_A(25),
|
|
|
|
FUNCTION_DESC_GPIO_INPUT_B(0),
|
|
FUNCTION_DESC_GPIO_INPUT_B(1),
|
|
FUNCTION_DESC_GPIO_INPUT_B(2),
|
|
FUNCTION_DESC_GPIO_INPUT_B(3),
|
|
FUNCTION_DESC_GPIO_INPUT_B(4),
|
|
FUNCTION_DESC_GPIO_INPUT_B(5),
|
|
FUNCTION_DESC_GPIO_INPUT_B(6),
|
|
FUNCTION_DESC_GPIO_INPUT_B(7),
|
|
|
|
FUNCTION_DESC_GPIO_INPUT_B(8),
|
|
FUNCTION_DESC_GPIO_INPUT_B(9),
|
|
FUNCTION_DESC_GPIO_INPUT_B(10),
|
|
FUNCTION_DESC_GPIO_INPUT_B(11),
|
|
FUNCTION_DESC_GPIO_INPUT_B(12),
|
|
FUNCTION_DESC_GPIO_INPUT_B(13),
|
|
FUNCTION_DESC_GPIO_INPUT_B(14),
|
|
FUNCTION_DESC_GPIO_INPUT_B(15),
|
|
|
|
FUNCTION_DESC_GPIO_INPUT_B(16),
|
|
FUNCTION_DESC_GPIO_INPUT_B(17),
|
|
FUNCTION_DESC_GPIO_INPUT_B(18),
|
|
FUNCTION_DESC_GPIO_INPUT_B(19),
|
|
FUNCTION_DESC_GPIO_INPUT_B(20),
|
|
FUNCTION_DESC_GPIO_INPUT_B(21),
|
|
FUNCTION_DESC_GPIO_INPUT_B(22),
|
|
FUNCTION_DESC_GPIO_INPUT_B(23),
|
|
|
|
FUNCTION_DESC_GPIO_INPUT_B(24),
|
|
FUNCTION_DESC_GPIO_INPUT_B(25),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(0),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(1),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(2),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(3),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(4),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(5),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(6),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(7),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(8),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(9),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(10),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(11),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(12),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(13),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(14),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(15),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(16),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(17),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(18),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(19),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(20),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(21),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(22),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(23),
|
|
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(24),
|
|
FUNCTION_DESC_GPIO_OUTPUT_B(25),
|
|
|
|
FUNCTION_DESC_GPIO(),
|
|
|
|
FUNCTION_DESC(MAX96745_I2C),
|
|
FUNCTION_DESC(MAX96745_UART),
|
|
};
|
|
|
|
static struct serdes_chip_pinctrl_info max96745_pinctrl_info = {
|
|
.pins = max96745_pins_desc,
|
|
.num_pins = ARRAY_SIZE(max96745_pins_desc),
|
|
.groups = max96745_groups_desc,
|
|
.num_groups = ARRAY_SIZE(max96745_groups_desc),
|
|
.functions = max96745_functions_desc,
|
|
.num_functions = ARRAY_SIZE(max96745_functions_desc),
|
|
};
|
|
|
|
static bool max96745_vid_tx_active(struct serdes *serdes)
|
|
{
|
|
u32 val;
|
|
int i = 0, ret = 0;
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
ret = serdes_reg_read(serdes, 0x0107, &val);
|
|
if (!ret)
|
|
break;
|
|
|
|
SERDES_DBG_CHIP("serdes %s: false val=%d i=%d ret=%d\n", __func__, val, i, ret);
|
|
msleep(20);
|
|
}
|
|
|
|
if (ret) {
|
|
SERDES_DBG_CHIP("serdes %s: false val=%d ret=%d\n", __func__, val, ret);
|
|
return false;
|
|
}
|
|
|
|
if (!FIELD_GET(VID_TX_ACTIVE_A | VID_TX_ACTIVE_B, val)) {
|
|
SERDES_DBG_CHIP("serdes %s: false val=%d\n", __func__, val);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int max96745_bridge_init(struct serdes *serdes)
|
|
{
|
|
if (max96745_vid_tx_active(serdes)) {
|
|
extcon_set_state(serdes->extcon, EXTCON_JACK_VIDEO_OUT, true);
|
|
pr_info("serdes %s, extcon is true state=%d\n", __func__, serdes->extcon->state);
|
|
} else {
|
|
pr_info("serdes %s, extcon is false\n", __func__);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool max96745_bridge_link_locked(struct serdes *serdes)
|
|
{
|
|
u32 val = 0, i;
|
|
|
|
if (serdes->lock_gpio) {
|
|
for (i = 0; i < 3; i++) {
|
|
val = gpiod_get_value_cansleep(serdes->lock_gpio);
|
|
if (val)
|
|
break;
|
|
msleep(20);
|
|
}
|
|
|
|
SERDES_DBG_CHIP("%s:%s-%s, gpio %s\n", __func__, dev_name(serdes->dev),
|
|
serdes->chip_data->name, (val) ? "locked" : "unlocked");
|
|
if (val)
|
|
return true;
|
|
}
|
|
|
|
if (serdes_reg_read(serdes, 0x002a, &val)) {
|
|
SERDES_DBG_CHIP("serdes %s: unlocked val=0x%x\n", __func__, val);
|
|
return false;
|
|
}
|
|
|
|
if (!FIELD_GET(LINK_LOCKED, val)) {
|
|
SERDES_DBG_CHIP("serdes %s: unlocked val=0x%x\n", __func__, val);
|
|
return false;
|
|
}
|
|
|
|
SERDES_DBG_CHIP("%s: serdes reg locked 0x%x\n", __func__, val);
|
|
|
|
return true;
|
|
}
|
|
|
|
static int max96745_bridge_attach(struct serdes *serdes)
|
|
{
|
|
if (max96745_bridge_link_locked(serdes))
|
|
serdes->serdes_bridge->status = connector_status_connected;
|
|
else
|
|
serdes->serdes_bridge->status = connector_status_disconnected;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static enum drm_connector_status
|
|
max96745_bridge_detect(struct serdes *serdes)
|
|
{
|
|
struct serdes_bridge *serdes_bridge = serdes->serdes_bridge;
|
|
enum drm_connector_status status = connector_status_connected;
|
|
|
|
if (!drm_kms_helper_is_poll_worker())
|
|
return serdes_bridge->status;
|
|
|
|
if (!max96745_bridge_link_locked(serdes)) {
|
|
status = connector_status_disconnected;
|
|
goto out;
|
|
}
|
|
|
|
if (extcon_get_state(serdes->extcon, EXTCON_JACK_VIDEO_OUT)) {
|
|
u32 dprx_trn_status2;
|
|
|
|
if (atomic_cmpxchg(&serdes_bridge->triggered, 1, 0)) {
|
|
status = connector_status_disconnected;
|
|
SERDES_DBG_CHIP("1 status=%d state=%d\n", status, serdes->extcon->state);
|
|
goto out;
|
|
}
|
|
|
|
if (serdes_reg_read(serdes, 0x641a, &dprx_trn_status2)) {
|
|
status = connector_status_disconnected;
|
|
SERDES_DBG_CHIP("2 status=%d state=%d\n", status, serdes->extcon->state);
|
|
goto out;
|
|
}
|
|
|
|
if ((dprx_trn_status2 & DPRX_TRAIN_STATE) != DPRX_TRAIN_STATE) {
|
|
dev_err(serdes->dev, "Training State: 0x%lx\n",
|
|
FIELD_GET(DPRX_TRAIN_STATE, dprx_trn_status2));
|
|
status = connector_status_disconnected;
|
|
SERDES_DBG_CHIP("3 status=%d state=%d\n", status, serdes->extcon->state);
|
|
goto out;
|
|
}
|
|
} else {
|
|
atomic_set(&serdes_bridge->triggered, 0);
|
|
SERDES_DBG_CHIP("4 status=%d state=%d\n", status, serdes->extcon->state);
|
|
}
|
|
|
|
if (serdes_bridge->next_bridge && (serdes_bridge->next_bridge->ops & DRM_BRIDGE_OP_DETECT))
|
|
return drm_bridge_detect(serdes_bridge->next_bridge);
|
|
|
|
out:
|
|
serdes_bridge->status = status;
|
|
SERDES_DBG_CHIP("%s:%s %s, status=%d state=%d\n", __func__, dev_name(serdes->dev),
|
|
serdes->chip_data->name,
|
|
status, serdes->extcon->state);
|
|
return status;
|
|
}
|
|
|
|
static int max96745_bridge_enable(struct serdes *serdes)
|
|
{
|
|
int ret = 0;
|
|
|
|
SERDES_DBG_CHIP("%s: serdes chip %s ret=%d state=%d\n",
|
|
__func__, serdes->chip_data->name, ret, serdes->extcon->state);
|
|
return ret;
|
|
}
|
|
|
|
static int max96745_bridge_disable(struct serdes *serdes)
|
|
{
|
|
int ret = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static struct serdes_chip_bridge_ops max96745_bridge_ops = {
|
|
.init = max96745_bridge_init,
|
|
.attach = max96745_bridge_attach,
|
|
.detect = max96745_bridge_detect,
|
|
.enable = max96745_bridge_enable,
|
|
.disable = max96745_bridge_disable,
|
|
};
|
|
|
|
static int max96745_pinctrl_set_mux(struct serdes *serdes,
|
|
unsigned int function, unsigned int group)
|
|
{
|
|
struct serdes_pinctrl *pinctrl = serdes->pinctrl;
|
|
struct function_desc *func;
|
|
struct group_desc *grp;
|
|
int i;
|
|
|
|
func = pinmux_generic_get_function(pinctrl->pctl, function);
|
|
if (!func)
|
|
return -EINVAL;
|
|
|
|
grp = pinctrl_generic_get_group(pinctrl->pctl, group);
|
|
if (!grp)
|
|
return -EINVAL;
|
|
|
|
SERDES_DBG_CHIP("%s: serdes chip %s func=%s data=%p group=%s data=%p, num_pin=%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 *data = func->data;
|
|
|
|
for (i = 0; i < grp->num_pins; i++) {
|
|
serdes_set_bits(serdes,
|
|
GPIO_A_REG(grp->pins[i] - pinctrl->pin_base),
|
|
GPIO_OUT_DIS,
|
|
FIELD_PREP(GPIO_OUT_DIS, data->gpio_out_dis));
|
|
serdes_set_bits(serdes,
|
|
GPIO_B_REG(grp->pins[i] - pinctrl->pin_base),
|
|
OUT_TYPE,
|
|
FIELD_PREP(OUT_TYPE, 1));
|
|
if (data->gpio_tx_en_a || data->gpio_tx_en_b)
|
|
serdes_set_bits(serdes,
|
|
GPIO_B_REG(grp->pins[i] - pinctrl->pin_base),
|
|
GPIO_TX_ID,
|
|
FIELD_PREP(GPIO_TX_ID, data->gpio_tx_id));
|
|
if (data->gpio_rx_en_a || data->gpio_rx_en_b)
|
|
serdes_set_bits(serdes,
|
|
GPIO_C_REG(grp->pins[i] - pinctrl->pin_base),
|
|
GPIO_RX_ID,
|
|
FIELD_PREP(GPIO_RX_ID, data->gpio_rx_id));
|
|
serdes_set_bits(serdes,
|
|
GPIO_D_REG(grp->pins[i] - pinctrl->pin_base),
|
|
GPIO_TX_EN_A | GPIO_TX_EN_B | GPIO_IO_RX_EN |
|
|
GPIO_RX_EN_A | GPIO_RX_EN_B,
|
|
FIELD_PREP(GPIO_TX_EN_A, data->gpio_tx_en_a) |
|
|
FIELD_PREP(GPIO_TX_EN_B, data->gpio_tx_en_b) |
|
|
FIELD_PREP(GPIO_RX_EN_A, data->gpio_rx_en_a) |
|
|
FIELD_PREP(GPIO_RX_EN_B, data->gpio_rx_en_b) |
|
|
FIELD_PREP(GPIO_IO_RX_EN, data->gpio_io_rx_en));
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max96745_pinctrl_config_get(struct serdes *serdes,
|
|
unsigned int pin, unsigned long *config)
|
|
{
|
|
enum pin_config_param param = pinconf_to_config_param(*config);
|
|
unsigned int gpio_a_reg, gpio_b_reg;
|
|
u16 arg = 0;
|
|
|
|
serdes_reg_read(serdes, GPIO_A_REG(pin), &gpio_a_reg);
|
|
serdes_reg_read(serdes, GPIO_B_REG(pin), &gpio_b_reg);
|
|
|
|
SERDES_DBG_CHIP("%s: serdes chip %s pin=%d param=%d\n", __func__, serdes->chip_data->name, pin, param);
|
|
|
|
switch (param) {
|
|
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
|
if (FIELD_GET(OUT_TYPE, gpio_b_reg))
|
|
return -EINVAL;
|
|
break;
|
|
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
|
if (!FIELD_GET(OUT_TYPE, gpio_b_reg))
|
|
return -EINVAL;
|
|
break;
|
|
case PIN_CONFIG_BIAS_DISABLE:
|
|
if (FIELD_GET(PULL_UPDN_SEL, gpio_b_reg) != 0)
|
|
return -EINVAL;
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_UP:
|
|
if (FIELD_GET(PULL_UPDN_SEL, gpio_b_reg) != 1)
|
|
return -EINVAL;
|
|
switch (FIELD_GET(RES_CFG, gpio_a_reg)) {
|
|
case 0:
|
|
arg = 40000;
|
|
break;
|
|
case 1:
|
|
arg = 10000;
|
|
break;
|
|
}
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
if (FIELD_GET(PULL_UPDN_SEL, gpio_b_reg) != 2)
|
|
return -EINVAL;
|
|
switch (FIELD_GET(RES_CFG, gpio_a_reg)) {
|
|
case 0:
|
|
arg = 40000;
|
|
break;
|
|
case 1:
|
|
arg = 10000;
|
|
break;
|
|
}
|
|
break;
|
|
case PIN_CONFIG_OUTPUT:
|
|
if (FIELD_GET(GPIO_OUT_DIS, gpio_a_reg))
|
|
return -EINVAL;
|
|
|
|
arg = FIELD_GET(GPIO_OUT, gpio_a_reg);
|
|
break;
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
*config = pinconf_to_config_packed(param, arg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max96745_pinctrl_config_set(struct serdes *serdes,
|
|
unsigned int pin, unsigned long *configs,
|
|
unsigned int num_configs)
|
|
{
|
|
enum pin_config_param param;
|
|
u32 arg;
|
|
u8 res_cfg;
|
|
int i;
|
|
|
|
for (i = 0; i < num_configs; i++) {
|
|
param = pinconf_to_config_param(configs[i]);
|
|
arg = pinconf_to_config_argument(configs[i]);
|
|
|
|
SERDES_DBG_CHIP("%s: serdes chip %s pin=%d param=%d\n", __func__,
|
|
serdes->chip_data->name, pin, param);
|
|
|
|
switch (param) {
|
|
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
|
serdes_set_bits(serdes, GPIO_B_REG(pin),
|
|
OUT_TYPE, FIELD_PREP(OUT_TYPE, 0));
|
|
break;
|
|
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
|
serdes_set_bits(serdes, GPIO_B_REG(pin),
|
|
OUT_TYPE, FIELD_PREP(OUT_TYPE, 1));
|
|
break;
|
|
case PIN_CONFIG_BIAS_DISABLE:
|
|
serdes_set_bits(serdes, GPIO_C_REG(pin),
|
|
PULL_UPDN_SEL,
|
|
FIELD_PREP(PULL_UPDN_SEL, 0));
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_UP:
|
|
switch (arg) {
|
|
case 40000:
|
|
res_cfg = 0;
|
|
break;
|
|
case 1000000:
|
|
res_cfg = 1;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
serdes_set_bits(serdes, GPIO_A_REG(pin),
|
|
RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
|
|
serdes_set_bits(serdes, GPIO_C_REG(pin),
|
|
PULL_UPDN_SEL,
|
|
FIELD_PREP(PULL_UPDN_SEL, 1));
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
switch (arg) {
|
|
case 40000:
|
|
res_cfg = 0;
|
|
break;
|
|
case 1000000:
|
|
res_cfg = 1;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
serdes_set_bits(serdes, GPIO_A_REG(pin),
|
|
RES_CFG, FIELD_PREP(RES_CFG, res_cfg));
|
|
serdes_set_bits(serdes, GPIO_C_REG(pin),
|
|
PULL_UPDN_SEL,
|
|
FIELD_PREP(PULL_UPDN_SEL, 2));
|
|
break;
|
|
case PIN_CONFIG_OUTPUT:
|
|
serdes_set_bits(serdes, GPIO_A_REG(pin),
|
|
GPIO_OUT_DIS | GPIO_OUT,
|
|
FIELD_PREP(GPIO_OUT_DIS, 0) |
|
|
FIELD_PREP(GPIO_OUT, arg));
|
|
break;
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct serdes_chip_pinctrl_ops max96745_pinctrl_ops = {
|
|
.pin_config_get = max96745_pinctrl_config_get,
|
|
.pin_config_set = max96745_pinctrl_config_set,
|
|
.set_mux = max96745_pinctrl_set_mux,
|
|
};
|
|
|
|
static int max96745_gpio_direction_input(struct serdes *serdes, int gpio)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96745_gpio_direction_output(struct serdes *serdes, int gpio, int value)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96745_gpio_get_level(struct serdes *serdes, int gpio)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96745_gpio_set_level(struct serdes *serdes, int gpio, int value)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96745_gpio_set_config(struct serdes *serdes, int gpio, unsigned long config)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96745_gpio_to_irq(struct serdes *serdes, int gpio)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static struct serdes_chip_gpio_ops max96745_gpio_ops = {
|
|
.direction_input = max96745_gpio_direction_input,
|
|
.direction_output = max96745_gpio_direction_output,
|
|
.get_level = max96745_gpio_get_level,
|
|
.set_level = max96745_gpio_set_level,
|
|
.set_config = max96745_gpio_set_config,
|
|
.to_irq = max96745_gpio_to_irq,
|
|
};
|
|
|
|
static int max96745_select(struct serdes *serdes, int chan)
|
|
{
|
|
/*0076 for linkA and 0086 for linkB*/
|
|
if (chan == DUAL_LINK) {
|
|
serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 0));
|
|
serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 0));
|
|
SERDES_DBG_CHIP("%s: enable %s remote i2c of linkA and linkB\n", __func__,
|
|
serdes->chip_data->name);
|
|
} else if (chan == LINKA) {
|
|
serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 0));
|
|
serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 1));
|
|
SERDES_DBG_CHIP("%s: only enable %s remote i2c of linkA\n", __func__,
|
|
serdes->chip_data->name);
|
|
} else if (chan == LINKB) {
|
|
serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 1));
|
|
serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 0));
|
|
SERDES_DBG_CHIP("%s: only enable %s remote i2c of linkB\n", __func__,
|
|
serdes->chip_data->name);
|
|
} else if (chan == SPLITTER_MODE) {
|
|
serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 0));
|
|
serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 0));
|
|
SERDES_DBG_CHIP("%s: enable %s remote i2c of linkA and linkB\n", __func__,
|
|
serdes->chip_data->name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max96745_deselect(struct serdes *serdes, int chan)
|
|
{
|
|
|
|
if (chan == DUAL_LINK) {
|
|
serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 1));
|
|
serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 1));
|
|
SERDES_DBG_CHIP("%s: disable %s remote i2c of linkA and linkB\n", __func__,
|
|
serdes->chip_data->name);
|
|
} else if (chan == LINKA) {
|
|
serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 1));
|
|
serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 0));
|
|
SERDES_DBG_CHIP("%s: only disable %s remote i2c of linkA\n", __func__,
|
|
serdes->chip_data->name);
|
|
} else if (chan == LINKB) {
|
|
serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 0));
|
|
serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 1));
|
|
SERDES_DBG_CHIP("%s: only disable %s remote i2c of linkB\n", __func__,
|
|
serdes->chip_data->name);
|
|
} else if (chan == SPLITTER_MODE) {
|
|
serdes_set_bits(serdes, 0x0076, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 1));
|
|
serdes_set_bits(serdes, 0x0086, DIS_REM_CC,
|
|
FIELD_PREP(DIS_REM_CC, 1));
|
|
SERDES_DBG_CHIP("%s: disable %s remote i2c of linkA and linkB\n", __func__,
|
|
serdes->chip_data->name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static struct serdes_chip_split_ops max96745_split_ops = {
|
|
.select = max96745_select,
|
|
.deselect = max96745_deselect,
|
|
};
|
|
|
|
static const struct check_reg_data max96745_improtant_reg[10] = {
|
|
{
|
|
"MAX96745 LINK LOCK",
|
|
{ 0x0013, (1 << 3) },
|
|
}, {
|
|
"MAX96745 LINKA LOCK",
|
|
{ 0x002A, (1 << 0) },
|
|
}, {
|
|
"MAX96745 LINKB LOCK",
|
|
{ 0x0034, (1 << 0) },
|
|
}, {
|
|
"MAX96745 X PCLK DET",
|
|
{ 0x0102, (1 << 7) },
|
|
}, {
|
|
"MAX96745 Y PCLK DET",
|
|
{ 0x0112, (1 << 7) },
|
|
},
|
|
};
|
|
|
|
static int max96745_check_reg(struct serdes *serdes)
|
|
{
|
|
int i = 0, ret = 0;
|
|
unsigned int val = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(max96745_improtant_reg); i++) {
|
|
if (!max96745_improtant_reg[i].seq.reg)
|
|
break;
|
|
|
|
ret = serdes_reg_read(serdes, max96745_improtant_reg[i].seq.reg, &val);
|
|
if (!ret && !(val & max96745_improtant_reg[i].seq.def)
|
|
&& (!atomic_read(&serdes->flag_early_suspend)))
|
|
dev_info(serdes->dev, "warning %s %s reg[0x%x] = 0x%x\n", __func__,
|
|
max96745_improtant_reg[i].name,
|
|
max96745_improtant_reg[i].seq.reg, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct serdes_check_reg_ops max96745_check_reg_ops = {
|
|
.check_reg = max96745_check_reg,
|
|
};
|
|
|
|
static int max96745_pm_suspend(struct serdes *serdes)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96745_pm_resume(struct serdes *serdes)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static struct serdes_chip_pm_ops max96745_pm_ops = {
|
|
.suspend = max96745_pm_suspend,
|
|
.resume = max96745_pm_resume,
|
|
};
|
|
|
|
static int max96745_irq_lock_handle(struct serdes *serdes)
|
|
{
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static int max96745_irq_err_handle(struct serdes *serdes)
|
|
{
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static struct serdes_chip_irq_ops max96745_irq_ops = {
|
|
.lock_handle = max96745_irq_lock_handle,
|
|
.err_handle = max96745_irq_err_handle,
|
|
};
|
|
|
|
struct serdes_chip_data serdes_max96745_data = {
|
|
.name = "max96745",
|
|
.serdes_type = TYPE_SER,
|
|
.serdes_id = MAXIM_ID_MAX96745,
|
|
.connector_type = DRM_MODE_CONNECTOR_eDP,
|
|
.regmap_config = &max96745_regmap_config,
|
|
.pinctrl_info = &max96745_pinctrl_info,
|
|
.bridge_ops = &max96745_bridge_ops,
|
|
.pinctrl_ops = &max96745_pinctrl_ops,
|
|
.gpio_ops = &max96745_gpio_ops,
|
|
.split_ops = &max96745_split_ops,
|
|
.check_ops = &max96745_check_reg_ops,
|
|
.pm_ops = &max96745_pm_ops,
|
|
.irq_ops = &max96745_irq_ops,
|
|
};
|
|
EXPORT_SYMBOL_GPL(serdes_max96745_data);
|
|
|
|
MODULE_LICENSE("GPL");
|