mfd: display-serdes: add serdes display driver support base on mfd arch

* i2c register initialization with dts sequence from serdes chip vendor.
* pinctrl and gpio interface to operate the different serdes chips.
* bridge interface to transmit data for different ser chips.
* panel interface to drive lcds for different des chips.
* one ser chip to connect two des chips in order to costdown.
* support different serdes display chip such as maxim, rohm and rockchip.

Signed-off-by: Luo Wei <lw@rock-chips.com>
Change-Id: Ic8f3558b8ea8ee3d5297bdf2551308e82925304a
This commit is contained in:
Luo Wei
2023-07-25 19:14:23 +08:00
committed by Tao Huang
parent 22d153d2eb
commit 563845b474
38 changed files with 8223 additions and 0 deletions

View File

@@ -1218,6 +1218,7 @@ config MFD_RK1000
if you say yes here you get support for the RK1000, with func as
TVEncoder or CODEC.
source "drivers/mfd/display-serdes/Kconfig"
source "drivers/mfd/rkx110_x120/Kconfig"
config MFD_RN5T618

View File

@@ -230,6 +230,7 @@ obj-$(CONFIG_MFD_RK806) += rk806-core.o
obj-$(CONFIG_MFD_RK806_SPI) += rk806-spi.o
obj-$(CONFIG_MFD_RK808) += rk808.o
obj-$(CONFIG_MFD_RK1000) += rk1000-core.o
obj-$(CONFIG_MFD_SERDES_DISPLAY) += display-serdes/
obj-y += rkx110_x120/
obj-$(CONFIG_MFD_RN5T618) += rn5t618.o
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o

View File

@@ -0,0 +1,31 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Multifunction miscellaneous devices
#
comment "driver for different display serdes"
menuconfig MFD_SERDES_DISPLAY
tristate "rockchip display serdes drivers support"
select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_MIPI_DSI
select SERDES_DISPLAY_CHIP_ROHM
select SERDES_DISPLAY_CHIP_MAXIM
select SERDES_DISPLAY_CHIP_ROCKCHIP
select SERDES_DISPLAY_CHIP_NOVO
select MFD_CORE
select REGMAP_I2C
select GENERIC_PINCTRL_GROUPS
select GENERIC_PINMUX_FUNCTIONS
default n
help
This driver supports different serdes devices from different vendor such as
maxim, rohm, rockchip etc.
if MFD_SERDES_DISPLAY
source "drivers/mfd/display-serdes/maxim/Kconfig"
source "drivers/mfd/display-serdes/rohm/Kconfig"
source "drivers/mfd/display-serdes/rockchip/Kconfig"
source "drivers/mfd/display-serdes/novo/Kconfig"
endif

View File

@@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for multifunction miscellaneous devices that just used for display
#
obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM) += maxim/
obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROHM) += rohm/
obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP) += rockchip/
obj-$(CONFIG_SERDES_DISPLAY_CHIP_NOVO) += novo/
serdes-mfd-display-$(CONFIG_MFD_SERDES_DISPLAY) += serdes-core.o serdes-irq.o
obj-$(CONFIG_MFD_SERDES_DISPLAY) += serdes-mfd-display.o serdes-i2c.o serdes-bridge.o serdes-panel.o serdes-gpio.o serdes-pinctrl.o

View File

@@ -0,0 +1,353 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* core.h -- core define for mfd display arch
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*
*/
#ifndef __MFD_SERDES_CORE_H__
#define __MFD_SERDES_CORE_H__
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/regulator/consumer.h>
#include <linux/backlight.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
#include <linux/extcon-provider.h>
#include <linux/bitfield.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_of.h>
#include <drm/drm_connector.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_modes.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <video/videomode.h>
#include <video/of_display_timing.h>
#include <video/display_timing.h>
#include <uapi/linux/media-bus-format.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinmux.h>
#include <asm/unaligned.h>
#include "gpio.h"
#include "../../../../drivers/pinctrl/core.h"
#include "../../../../drivers/pinctrl/pinconf.h"
#include "../../../../drivers/pinctrl/pinmux.h"
#include "../../../../drivers/gpio/gpiolib.h"
/*
* if enable all the debug information,
* there will be much log.
*
* so suggest set CONFIG_LOG_BUF_SHIFT to 18
*/
//#define SERDES_DEBUG_MFD
//#define SERDES_DEBUG_I2C
//#define SERDES_DEBUG_CHIP
#ifdef SERDES_DEBUG_MFD
#define SERDES_DBG_MFD(x...) pr_info(x)
#else
#define SERDES_DBG_MFD(x...) no_printk(x)
#endif
#ifdef SERDES_DEBUG_I2C
#define SERDES_DBG_I2C(x...) pr_info(x)
#else
#define SERDES_DBG_I2C(x...) no_printk(x)
#endif
#ifdef SERDES_DEBUG_CHIP
#define SERDES_DBG_CHIP(x...) pr_info(x)
#else
#define SERDES_DBG_CHIP(x...) no_printk(x)
#endif
#define MFD_SERDES_DISPLAY_VERSION "serdes-mfd-displaly-v10-230901"
struct serdes;
struct serdes_chip_pinctrl_info {
struct pinctrl_pin_desc *pins;
unsigned int num_pins;
struct group_desc *groups;
unsigned int num_groups;
struct function_desc *functions;
unsigned int num_functions;
};
struct serdes_chip_bridge_ops {
/* serdes chip function for bridge */
int (*power_on)(struct serdes *serdes);
int (*init)(struct serdes *serdes);
int (*attach)(struct serdes *serdes);
enum drm_connector_status (*detect)(struct serdes *serdes);
int (*get_modes)(struct serdes *serdes);
int (*pre_enable)(struct serdes *serdes);
int (*enable)(struct serdes *serdes);
int (*disable)(struct serdes *serdes);
int (*post_disable)(struct serdes *serdes);
};
struct serdes_chip_panel_ops {
/*serdes chip function for bridge*/
int (*power_on)(struct serdes *serdes);
int (*init)(struct serdes *serdes);
int (*disable)(struct serdes *serdes);
int (*unprepare)(struct serdes *serdes);
int (*prepare)(struct serdes *serdes);
int (*enable)(struct serdes *serdes);
int (*get_modes)(struct serdes *serdes);
int (*backlight_enable)(struct serdes *serdes);
int (*backlight_disable)(struct serdes *serdes);
};
struct serdes_chip_pinctrl_ops {
/* serdes chip pinctrl function */
int (*pin_config_get)(struct serdes *serdes,
unsigned int pin,
unsigned long *config);
int (*pin_config_set)(struct serdes *serdes,
unsigned int pin,
unsigned long *configs,
unsigned int num_configs);
int (*set_mux)(struct serdes *serdes, unsigned int func_selector,
unsigned int group_selector);
};
struct serdes_chip_gpio_ops {
/* serdes chip gpio function */
int (*direction_input)(struct serdes *serdes, int gpio);
int (*direction_output)(struct serdes *serdes, int gpio, int value);
int (*get_level)(struct serdes *serdes, int gpio);
int (*set_level)(struct serdes *serdes, int gpio, int value);
int (*set_config)(struct serdes *serdes, int gpio, unsigned long config);
int (*to_irq)(struct serdes *serdes, int gpio);
};
struct serdes_chip_pm_ops {
/* serdes chip function for suspend and resume */
int (*suspend)(struct serdes *serdes);
int (*resume)(struct serdes *serdes);
};
struct serdes_chip_irq_ops {
/* serdes chip function for lock and err irq */
int (*lock_handle)(struct serdes *serdes);
int (*err_handle)(struct serdes *serdes);
};
struct serdes_chip_data {
const char *name;
enum serdes_type serdes_type;
enum serdes_id serdes_id;
enum serdes_bridge_type bridge_type;
int sequence_init;
int connector_type;
int reg_id;
int id_data;
int int_status_reg;
int int_trig;
int num_gpio;
int gpio_base;
int same_chip_count;
u8 bank_num;
struct regmap_config *regmap_config;
struct serdes_chip_pinctrl_info *pinctrl_info;
struct serdes_chip_bridge_ops *bridge_ops;
struct serdes_chip_panel_ops *panel_ops;
struct serdes_chip_pinctrl_ops *pinctrl_ops;
struct serdes_chip_gpio_ops *gpio_ops;
struct serdes_chip_pm_ops *pm_ops;
struct serdes_chip_irq_ops *irq_ops;
};
struct serdes_init_seq {
struct reg_sequence *reg_sequence;
unsigned int reg_seq_cnt;
};
struct serdes_gpio {
struct device *dev;
struct serdes_pinctrl *parent;
struct regmap *regmap;
struct gpio_chip gpio_chip;
};
struct serdes_pinctrl {
struct device *dev;
struct serdes *parent;
struct pinctrl_dev *pctl;
struct pinctrl_pin_desc *pdesc;
struct regmap *regmap;
struct pinctrl_desc *pinctrl_desc;
struct serdes_gpio *gpio;
int pin_base;
};
struct serdes_panel {
struct drm_panel panel;
enum drm_connector_status status;
struct drm_connector connector;
const char *name;
u32 width_mm;
u32 height_mm;
u32 link_rate;
u32 lane_count;
bool ssc;
struct device *dev;
struct serdes *parent;
struct regmap *regmap;
struct mipi_dsi_device *dsi;
struct device_node *dsi_node;
struct drm_display_mode mode;
struct backlight_device *backlight;
struct serdes_init_seq *serdes_init_seq;
bool sel_mipi;
bool dv_swp_ab;
bool dpi_deskew_en;
bool split_mode;
u32 num_lanes;
u32 dsi_lane_map[4];
};
struct serdes_bridge {
struct drm_bridge base_bridge;
struct drm_bridge *next_bridge;
enum drm_connector_status status;
atomic_t triggered;
struct drm_connector connector;
struct drm_panel *panel;
struct device *dev;
struct serdes *parent;
struct regmap *regmap;
struct mipi_dsi_device *dsi;
struct device_node *dsi_node;
struct drm_display_mode mode;
struct backlight_device *backlight;
bool sel_mipi;
bool dv_swp_ab;
bool dpi_deskew_en;
bool split_mode;
u32 num_lanes;
u32 dsi_lane_map[4];
};
struct serdes {
int num_gpio;
struct mutex io_lock;
struct mutex irq_lock;
struct mutex wq_lock;
struct device *dev;
enum serdes_type type;
struct regmap *regmap;
struct regulator *supply;
struct extcon_dev *extcon;
atomic_t conn_trigger;
/* serdes power and reset pin */
struct gpio_desc *reset_gpio;
struct gpio_desc *enable_gpio;
struct regulator *vpower;
/* serdes irq pin */
struct gpio_desc *lock_gpio;
struct gpio_desc *err_gpio;
int lock_irq;
int err_irq;
int lock_irq_trig;
int err_irq_trig;
atomic_t flag_ser_init;
struct workqueue_struct *mfd_wq;
struct delayed_work mfd_delay_work;
bool route_enable;
bool use_delay_work;
struct pinctrl *pinctrl_node;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_sleep;
struct serdes_init_seq *serdes_init_seq;
struct serdes_bridge *serdes_bridge;
struct serdes_panel *serdes_panel;
struct serdes_pinctrl *pinctrl;
struct serdes_chip_data *chip_data;
};
/* Device I/O API */
int serdes_reg_read(struct serdes *serdes, unsigned int reg, unsigned int *val);
int serdes_reg_write(struct serdes *serdes, unsigned int reg, unsigned int val);
void serdes_reg_lock(struct serdes *serdes);
int serdes_reg_unlock(struct serdes *serdes);
int serdes_set_bits(struct serdes *serdes, unsigned int reg,
unsigned int mask, unsigned int val);
int serdes_bulk_read(struct serdes *serdes, unsigned int reg,
int count, u16 *buf);
int serdes_bulk_write(struct serdes *serdes, unsigned int reg,
int count, void *src);
int serdes_multi_reg_write(struct serdes *serdes, const struct reg_sequence *regs,
int num_regs);
int serdes_i2c_set_sequence(struct serdes *serdes);
int serdes_device_init(struct serdes *serdes);
int serdes_set_pinctrl_default(struct serdes *serdes);
int serdes_set_pinctrl_sleep(struct serdes *serdes);
int serdes_device_suspend(struct serdes *serdes);
int serdes_device_resume(struct serdes *serdes);
void serdes_device_shutdown(struct serdes *serdes);
int serdes_irq_init(struct serdes *serdes);
void serdes_irq_exit(struct serdes *serdes);
void serdes_auxadc_init(struct serdes *serdes);
extern struct serdes_chip_data serdes_bu18tl82_data;
extern struct serdes_chip_data serdes_bu18rl82_data;
extern struct serdes_chip_data serdes_max96745_data;
extern struct serdes_chip_data serdes_max96752_data;
extern struct serdes_chip_data serdes_max96755_data;
extern struct serdes_chip_data serdes_max96772_data;
extern struct serdes_chip_data serdes_max96789_data;
extern struct serdes_chip_data serdes_rkx111_data;
extern struct serdes_chip_data serdes_rkx121_data;
extern struct serdes_chip_data serdes_nca9539_data;
#endif

View File

@@ -0,0 +1,248 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* gpio.h -- GPIO for different serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*
*/
#ifndef __MFD_SERDES_GPIO_H__
#define __MFD_SERDES_GPIO_H__
#include "core.h"
enum serdes_parent {
BU18TL82 = 0x1000,
BU18RL82 = 0x1001,
MAX96745 = 0x2000,
MAX96752 = 0x2001,
MAX96755 = 0x2003,
MAX96722 = 0x2004,
MAX96789 = 0x2005,
RKX111 = 0x3000,
RKX121 = 0x3001,
};
enum serdes_type {
TYPE_ID_INVALID = 0,
TYPE_SER,
TYPE_DES,
TYPE_OTHER,
};
enum serdes_bridge_type {
TYPE_BRIDGE_PANEL = 0,
TYPE_BRIDGE_BRIDGE,
};
enum serdes_id {
SERDES_ID_INVALID = 0,
ROHM_ID_BU18TL82,
ROHM_ID_BU18RL82,
MAXIM_ID_MAX96745,
MAXIM_ID_MAX96752,
MAXIM_ID_MAX96755,
MAXIM_ID_MAX96772,
MAXIM_ID_MAX96789,
ROCKCHIP_ID_RKX111,
ROCKCHIP_ID_RKX121,
NOVO_ID_NCA9539,
SERDES_NUM_ID,
};
enum bu18tl82_gpio_list {
ROHM_BU18TL82_GPIO0 = 0,
ROHM_BU18TL82_GPIO1,
ROHM_BU18TL82_GPIO2,
ROHM_BU18TL82_GPIO3,
ROHM_BU18TL82_GPIO4,
ROHM_BU18TL82_GPIO5,
ROHM_BU18TL82_GPIO6,
ROHM_BU18TL82_GPIO7,
};
enum bu18rl82_gpio_list {
ROHM_BU18RL82_GPIO0 = 0,
ROHM_BU18RL82_GPIO1,
ROHM_BU18RL82_GPIO2,
ROHM_BU18RL82_GPIO3,
ROHM_BU18RL82_GPIO4,
ROHM_BU18RL82_GPIO5,
ROHM_BU18RL82_GPIO6,
ROHM_BU18RL82_GPIO7,
};
enum max96745_gpio_list {
MAXIM_MAX96745_MFP0 = 0,
MAXIM_MAX96745_MFP1,
MAXIM_MAX96745_MFP2,
MAXIM_MAX96745_MFP3,
MAXIM_MAX96745_MFP4,
MAXIM_MAX96745_MFP5,
MAXIM_MAX96745_MFP6,
MAXIM_MAX96745_MFP7,
MAXIM_MAX96745_MFP8,
MAXIM_MAX96745_MFP9,
MAXIM_MAX96745_MFP10,
MAXIM_MAX96745_MFP11,
MAXIM_MAX96745_MFP12,
MAXIM_MAX96745_MFP13,
MAXIM_MAX96745_MFP14,
MAXIM_MAX96745_MFP15,
MAXIM_MAX96745_MFP16,
MAXIM_MAX96745_MFP17,
MAXIM_MAX96745_MFP18,
MAXIM_MAX96745_MFP19,
MAXIM_MAX96745_MFP20,
MAXIM_MAX96745_MFP21,
MAXIM_MAX96745_MFP22,
MAXIM_MAX96745_MFP23,
MAXIM_MAX96745_MFP24,
MAXIM_MAX96745_MFP25,
};
enum max96752_gpio_list {
MAXIM_MAX96752_MFP0 = 0,
MAXIM_MAX96752_MFP1,
MAXIM_MAX96752_MFP2,
MAXIM_MAX96752_MFP3,
MAXIM_MAX96752_MFP4,
MAXIM_MAX96752_MFP5,
MAXIM_MAX96752_MFP6,
MAXIM_MAX96752_MFP7,
MAXIM_MAX96752_MFP8,
MAXIM_MAX96752_MFP9,
MAXIM_MAX96752_MFP10,
MAXIM_MAX96752_MFP11,
MAXIM_MAX96752_MFP12,
MAXIM_MAX96752_MFP13,
MAXIM_MAX96752_MFP14,
MAXIM_MAX96752_MFP15,
};
enum max96755_gpio_list {
MAXIM_MAX96755_MFP0 = 0,
MAXIM_MAX96755_MFP1,
MAXIM_MAX96755_MFP2,
MAXIM_MAX96755_MFP3,
MAXIM_MAX96755_MFP4,
MAXIM_MAX96755_MFP5,
MAXIM_MAX96755_MFP6,
MAXIM_MAX96755_MFP7,
MAXIM_MAX96755_MFP8,
MAXIM_MAX96755_MFP9,
MAXIM_MAX96755_MFP10,
MAXIM_MAX96755_MFP11,
MAXIM_MAX96755_MFP12,
MAXIM_MAX96755_MFP13,
MAXIM_MAX96755_MFP14,
MAXIM_MAX96755_MFP15,
MAXIM_MAX96755_MFP16,
MAXIM_MAX96755_MFP17,
MAXIM_MAX96755_MFP18,
MAXIM_MAX96755_MFP19,
MAXIM_MAX96755_MFP20,
};
enum max96722_gpio_list {
MAXIM_MAX96772_MFP0 = 0,
MAXIM_MAX96772_MFP1,
MAXIM_MAX96772_MFP2,
MAXIM_MAX96772_MFP3,
MAXIM_MAX96772_MFP4,
MAXIM_MAX96772_MFP5,
MAXIM_MAX96772_MFP6,
MAXIM_MAX96772_MFP7,
MAXIM_MAX96772_MFP8,
MAXIM_MAX96772_MFP9,
MAXIM_MAX96772_MFP10,
MAXIM_MAX96772_MFP11,
MAXIM_MAX96772_MFP12,
MAXIM_MAX96772_MFP13,
MAXIM_MAX96772_MFP14,
MAXIM_MAX96772_MFP15,
};
enum max96789_gpio_list {
MAXIM_MAX96789_MFP0 = 0,
MAXIM_MAX96789_MFP1,
MAXIM_MAX96789_MFP2,
MAXIM_MAX96789_MFP3,
MAXIM_MAX96789_MFP4,
MAXIM_MAX96789_MFP5,
MAXIM_MAX96789_MFP6,
MAXIM_MAX96789_MFP7,
MAXIM_MAX96789_MFP8,
MAXIM_MAX96789_MFP9,
MAXIM_MAX96789_MFP10,
MAXIM_MAX96789_MFP11,
MAXIM_MAX96789_MFP12,
MAXIM_MAX96789_MFP13,
MAXIM_MAX96789_MFP14,
MAXIM_MAX96789_MFP15,
MAXIM_MAX96789_MFP16,
MAXIM_MAX96789_MFP17,
MAXIM_MAX96789_MFP18,
MAXIM_MAX96789_MFP19,
MAXIM_MAX96789_MFP20,
};
enum rkx111_gpio_list {
ROCKCHIP_RKX111_GPIO0 = 0,
ROCKCHIP_RKX111_GPIO1,
ROCKCHIP_RKX111_GPIO2,
ROCKCHIP_RKX111_GPIO3,
ROCKCHIP_RKX111_GPIO4,
ROCKCHIP_RKX111_GPIO5,
ROCKCHIP_RKX111_GPIO6,
ROCKCHIP_RKX111_GPIO7,
};
enum rkx121_gpio_list {
ROCKCHIP_RKX121_GPIO0 = 0,
ROCKCHIP_RKX121_GPIO1,
ROCKCHIP_RKX121_GPIO2,
ROCKCHIP_RKX121_GPIO3,
ROCKCHIP_RKX121_GPIO4,
ROCKCHIP_RKX121_GPIO5,
ROCKCHIP_RKX121_GPIO6,
ROCKCHIP_RKX121_GPIO7,
};
enum serdes_gpio_state {
SERDES_GPIO_PULL_NONE = 0,
SERDES_GPIO_PULL_DOWN,
SERDES_GPIO_PULL_UP,
SERDES_GPIO_DIR_IN,
SERDES_GPIO_DIR_OUT,
SERDES_GPIO_LEVEL_HIGH,
SERDES_GPIO_LEVEL_LOW,
};
enum nca9539_gpio_list {
NOVO_NCA9539_GPIO0 = 0,
NOVO_NCA9539_GPIO1,
NOVO_NCA9539_GPIO2,
NOVO_NCA9539_GPIO3,
NOVO_NCA9539_GPIO4,
NOVO_NCA9539_GPIO5,
NOVO_NCA9539_GPIO6,
NOVO_NCA9539_GPIO7,
NOVO_NCA9539_GPIO8,
NOVO_NCA9539_GPIO9,
NOVO_NCA9539_GPIO10,
NOVO_NCA9539_GPIO11,
NOVO_NCA9539_GPIO12,
NOVO_NCA9539_GPIO13,
NOVO_NCA9539_GPIO14,
NOVO_NCA9539_GPIO15,
};
#endif

View File

@@ -0,0 +1,44 @@
# SPDX-License-Identifier: GPL-2.0
#
# maxim display serdes drivers configuration
#
menuconfig SERDES_DISPLAY_CHIP_MAXIM
tristate "maxim serdes device support"
default y
help
Enable this to be able to choose the drivers for controlling the
maxim serdes.
if SERDES_DISPLAY_CHIP_MAXIM
config SERDES_DISPLAY_CHIP_MAXIM_MAX96745
tristate "maxim max96745 serdes"
default y
help
To support maxim max96745 display serdes.
config SERDES_DISPLAY_CHIP_MAXIM_MAX96752
tristate "maxim max96752 serdes"
default y
help
To support maxim max96752 display serdes.
config SERDES_DISPLAY_CHIP_MAXIM_MAX96755
tristate "maxim max96755 serdes"
default y
help
To support maxim max96755 display serdes.
config SERDES_DISPLAY_CHIP_MAXIM_MAX96772
tristate "maxim max96772 serdes"
default y
help
To support maxim max96772 display serdes.
config SERDES_DISPLAY_CHIP_MAXIM_MAX96789
tristate "maxim max96789 serdes"
default y
help
To support maxim max96789 display serdes.
endif

View File

@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
#
# maxim display serdes drivers configuration
#
obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96745) += maxim-max96745.o
obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96752) += maxim-max96752.o
obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96755) += maxim-max96755.o
obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96772) += maxim-max96772.o
obj-$(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96789) += maxim-max96789.o

View File

@@ -0,0 +1,781 @@
// 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 = "DES_GPIO"#id"_OUTPUT_A", \
.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 = "DES_GPIO"#id"_OUTPUT_B", \
.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_GPIO"#id"_INPUT_A", \
.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_GPIO"#id"_INPUT_B", \
.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;
if (serdes_reg_read(serdes, 0x0107, &val))
return false;
if (!FIELD_GET(VID_TX_ACTIVE_A | VID_TX_ACTIVE_B, 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("%s, extcon is true\n", __func__);
} else {
pr_info("%s, extcon is false\n", __func__);
}
return 0;
}
static bool max96745_bridge_link_locked(struct serdes *serdes)
{
u32 val;
if (serdes->lock_gpio)
return gpiod_get_value_cansleep(serdes->lock_gpio);
if (serdes_reg_read(serdes, 0x002a, &val))
return false;
if (!FIELD_GET(LINK_LOCKED, val))
return false;
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;
goto out;
}
if (serdes_reg_read(serdes, 0x641a, &dprx_trn_status2)) {
status = connector_status_disconnected;
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;
goto out;
}
} else {
atomic_set(&serdes_bridge->triggered, 0);
}
out:
serdes_bridge->status = status;
SERDES_DBG_MFD("%s: status=%d\n", __func__, status);
return status;
}
static int max96745_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 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_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 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));
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 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_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,
.pm_ops = &max96745_pm_ops,
.irq_ops = &max96745_irq_ops,
};
EXPORT_SYMBOL_GPL(serdes_max96745_data);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,139 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* maxim-max96745.h -- register define for max96745 chip
*
* Copyright (c) 2023 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*
*/
#ifndef __MFD_SERDES_MAXIM_MAX96745_H__
#define __MFD_SERDES_MAXIM_MAX96745_H__
#include <linux/bitfield.h>
#define GPIO_A_REG(gpio) (0x0200 + ((gpio) * 8))
#define GPIO_B_REG(gpio) (0x0201 + ((gpio) * 8))
#define GPIO_C_REG(gpio) (0x0202 + ((gpio) * 8))
#define GPIO_D_REG(gpio) (0x0203 + ((gpio) * 8))
/* 0005h */
#define PU_LF3 BIT(3)
#define PU_LF2 BIT(2)
#define PU_LF1 BIT(1)
#define PU_LF0 BIT(0)
/* 0010h */
#define RESET_ALL BIT(7)
#define SLEEP BIT(3)
/* 0011h */
#define CXTP_B BIT(2)
#define CXTP_A BIT(0)
/* 0013h */
#define LOCKED BIT(3)
#define ERROR BIT(2)
/* 0026h */
#define LF_0 GENMASK(2, 0)
#define LF_1 GENMASK(6, 4)
/* 0027h */
#define LF_2 GENMASK(2, 0)
#define LF_3 GENMASK(6, 4)
/* 0028h, 0032h */
#define LINK_EN BIT(7)
#define TX_RATE GENMASK(3, 2)
/* 0029h, 0033h */
#define RESET_LINK BIT(0)
#define RESET_ONESHOT BIT(1)
/* 002Ah, 0034h */
#define LINK_LOCKED BIT(0)
/* 0076h, 0086h */
#define DIS_REM_CC BIT(7)
/* 0100h */
#define VID_LINK_SEL GENMASK(2, 1)
#define VID_TX_EN BIT(0)
/* 0101h */
#define BPP GENMASK(5, 0)
/* 0102h */
#define PCLKDET_A BIT(7)
#define DRIFT_ERR_A BIT(6)
#define OVERFLOW_A BIT(5)
#define FIFO_WARN_A BIT(4)
#define LIM_HEART BIT(2)
/* 0107h */
#define VID_TX_ACTIVE_B BIT(7)
#define VID_TX_ACTIVE_A BIT(6)
/* 0108h */
#define PCLKDET_B BIT(7)
#define DRIFT_ERR_B BIT(6)
#define OVERFLOW_B BIT(5)
#define FIFO_WARN_B BIT(4)
/* 0200h */
#define RES_CFG BIT(7)
#define TX_COM_EN BIT(5)
#define GPIO_OUT BIT(4)
#define GPIO_IN BIT(3)
#define GPIO_OUT_DIS BIT(0)
/* 0201h */
#define PULL_UPDN_SEL GENMASK(7, 6)
#define OUT_TYPE BIT(5)
#define GPIO_TX_ID GENMASK(4, 0)
/* 0202h */
#define OVR_RES_CFG BIT(7)
#define IO_EDGE_RATE GENMASK(6, 5)
#define GPIO_RX_ID GENMASK(4, 0)
/* 0203h */
#define GPIO_IO_RX_EN BIT(5)
#define GPIO_OUT_LGC BIT(4)
#define GPIO_RX_EN_B BIT(3)
#define GPIO_TX_EN_B BIT(2)
#define GPIO_RX_EN_A BIT(1)
#define GPIO_TX_EN_A BIT(0)
/* 0750h */
#define FRCZEROPAD GENMASK(7, 6)
#define FRCZPEN BIT(5)
#define FRCSDGAIN BIT(4)
#define FRCSDEN BIT(3)
#define FRCGAIN GENMASK(2, 1)
#define FRCEN BIT(0)
/* 0751h */
#define FRCDATAWIDTH BIT(3)
#define FRCASYNCEN BIT(2)
#define FRCHSPOL BIT(1)
#define FRCVSPOL BIT(0)
/* 0752h */
#define FRCDCMODE GENMASK(1, 0)
/* 641Ah */
#define DPRX_TRAIN_STATE GENMASK(7, 4)
/* 7000h */
#define LINK_ENABLE BIT(0)
/* 7070h */
#define MAX_LANE_COUNT GENMASK(7, 0)
/* 7074h */
#define MAX_LINK_RATE GENMASK(7, 0)
#endif

View File

@@ -0,0 +1,319 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* maxim-max96752.c -- I2C register interface access for max96752 serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author:
*/
#include "../core.h"
#include "maxim-max96752.h"
static const struct regmap_range max96752_readable_ranges[] = {
regmap_reg_range(0x0000, 0x0600),
};
static const struct regmap_access_table max96752_readable_table = {
.yes_ranges = max96752_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(max96752_readable_ranges),
};
static struct regmap_config max96752_regmap_config = {
.name = "max96752",
.reg_bits = 16,
.val_bits = 8,
.max_register = 0xffff,
.rd_table = &max96752_readable_table,
};
static int MAX96752_MFP0_pins[] = {0};
static int MAX96752_MFP1_pins[] = {1};
static int MAX96752_MFP2_pins[] = {2};
static int MAX96752_MFP3_pins[] = {3};
static int MAX96752_MFP4_pins[] = {4};
static int MAX96752_MFP5_pins[] = {5};
static int MAX96752_MFP6_pins[] = {6};
static int MAX96752_MFP7_pins[] = {7};
static int MAX96752_MFP8_pins[] = {8};
static int MAX96752_MFP9_pins[] = {9};
static int MAX96752_MFP10_pins[] = {10};
static int MAX96752_MFP11_pins[] = {11};
static int MAX96752_MFP12_pins[] = {12};
static int MAX96752_MFP13_pins[] = {13};
static int MAX96752_MFP14_pins[] = {14};
static int MAX96752_MFP15_pins[] = {15};
#define GROUP_DESC(nm) \
{ \
.name = #nm, \
.pins = nm ## _pins, \
.num_pins = ARRAY_SIZE(nm ## _pins), \
}
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;
};
static const char *serdes_gpio_groups[] = {
"MAX96752_MFP0", "MAX96752_MFP1", "MAX96752_MFP2", "MAX96752_MFP3",
"MAX96752_MFP4", "MAX96752_MFP5", "MAX96752_MFP6", "MAX96752_MFP7",
"MAX96752_MFP8", "MAX96752_MFP9", "MAX96752_MFP10", "MAX96752_MFP11",
"MAX96752_MFP12", "MAX96752_MFP13", "MAX96752_MFP14", "MAX96752_MFP15",
};
#define FUNCTION_DESC_GPIO_INPUT(id) \
{ \
.name = "MFP"#id"_INPUT", \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
.data = (void *)(const struct serdes_function_data []) { \
{ .gpio_rx_en = 1, .gpio_rx_id = id } \
}, \
} \
#define FUNCTION_DESC_GPIO_OUTPUT(id) \
{ \
.name = "MFP"#id"_OUTPUT", \
.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 max96752_pins_desc[] = {
PINCTRL_PIN(MAXIM_MAX96752_MFP0, "MAX96752_MFP0"),
PINCTRL_PIN(MAXIM_MAX96752_MFP1, "MAX96752_MFP1"),
PINCTRL_PIN(MAXIM_MAX96752_MFP2, "MAX96752_MFP2"),
PINCTRL_PIN(MAXIM_MAX96752_MFP3, "MAX96752_MFP3"),
PINCTRL_PIN(MAXIM_MAX96752_MFP4, "MAX96752_MFP4"),
PINCTRL_PIN(MAXIM_MAX96752_MFP5, "MAX96752_MFP5"),
PINCTRL_PIN(MAXIM_MAX96752_MFP6, "MAX96752_MFP6"),
PINCTRL_PIN(MAXIM_MAX96752_MFP7, "MAX96752_MFP7"),
PINCTRL_PIN(MAXIM_MAX96752_MFP8, "MAX96752_MFP8"),
PINCTRL_PIN(MAXIM_MAX96752_MFP9, "MAX96752_MFP9"),
PINCTRL_PIN(MAXIM_MAX96752_MFP10, "MAX96752_MFP10"),
PINCTRL_PIN(MAXIM_MAX96752_MFP11, "MAX96752_MFP11"),
PINCTRL_PIN(MAXIM_MAX96752_MFP12, "MAX96752_MFP12"),
PINCTRL_PIN(MAXIM_MAX96752_MFP13, "MAX96752_MFP13"),
PINCTRL_PIN(MAXIM_MAX96752_MFP14, "MAX96752_MFP14"),
PINCTRL_PIN(MAXIM_MAX96752_MFP15, "MAX96752_MFP15"),
};
static struct group_desc max96752_groups_desc[] = {
GROUP_DESC(MAX96752_MFP0),
GROUP_DESC(MAX96752_MFP1),
GROUP_DESC(MAX96752_MFP2),
GROUP_DESC(MAX96752_MFP3),
GROUP_DESC(MAX96752_MFP4),
GROUP_DESC(MAX96752_MFP5),
GROUP_DESC(MAX96752_MFP6),
GROUP_DESC(MAX96752_MFP7),
GROUP_DESC(MAX96752_MFP8),
GROUP_DESC(MAX96752_MFP9),
GROUP_DESC(MAX96752_MFP10),
GROUP_DESC(MAX96752_MFP11),
GROUP_DESC(MAX96752_MFP12),
GROUP_DESC(MAX96752_MFP13),
GROUP_DESC(MAX96752_MFP14),
GROUP_DESC(MAX96752_MFP15),
};
static struct function_desc max96752_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_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),
};
static struct serdes_chip_pinctrl_info max96752_pinctrl_info = {
.pins = max96752_pins_desc,
.num_pins = ARRAY_SIZE(max96752_pins_desc),
.groups = max96752_groups_desc,
.num_groups = ARRAY_SIZE(max96752_groups_desc),
.functions = max96752_functions_desc,
.num_functions = ARRAY_SIZE(max96752_functions_desc),
};
static int max96752_panel_prepare(struct serdes *serdes)
{
return 0;
}
static int max96752_panel_unprepare(struct serdes *serdes)
{
//serdes_reg_write(serdes, 0x0215, 0x80); /* lcd_en */
return 0;
}
static int max96752_panel_enable(struct serdes *serdes)
{
return 0;
}
static int max96752_panel_disable(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_panel_ops max96752_panel_ops = {
.prepare = max96752_panel_prepare,
.unprepare = max96752_panel_unprepare,
.enable = max96752_panel_enable,
.disable = max96752_panel_disable,
};
static int max96752_pinctrl_config_get(struct serdes *serdes,
unsigned int pin,
unsigned long *config)
{
return 0;
}
static int max96752_pinctrl_config_set(struct serdes *serdes,
unsigned int pin,
unsigned long *configs,
unsigned int num_configs)
{
return 0;
}
static int max96752_pinctrl_set_mux(struct serdes *serdes, unsigned int func_selector,
unsigned int group_selector)
{
return 0;
}
static struct serdes_chip_pinctrl_ops max96752_pinctrl_ops = {
.pin_config_get = max96752_pinctrl_config_get,
.pin_config_set = max96752_pinctrl_config_set,
.set_mux = max96752_pinctrl_set_mux,
};
static int max96752_gpio_direction_input(struct serdes *serdes, int gpio)
{
return 0;
}
static int max96752_gpio_direction_output(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int max96752_gpio_get_level(struct serdes *serdes, int gpio)
{
return 0;
}
static int max96752_gpio_set_level(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int max96752_gpio_set_config(struct serdes *serdes, int gpio, unsigned long config)
{
return 0;
}
static int max96752_gpio_to_irq(struct serdes *serdes, int gpio)
{
return 0;
}
static struct serdes_chip_gpio_ops max96752_gpio_ops = {
.direction_input = max96752_gpio_direction_input,
.direction_output = max96752_gpio_direction_output,
.get_level = max96752_gpio_get_level,
.set_level = max96752_gpio_set_level,
.set_config = max96752_gpio_set_config,
.to_irq = max96752_gpio_to_irq,
};
static int max96752_pm_suspend(struct serdes *serdes)
{
return 0;
}
static int max96752_pm_resume(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_pm_ops max96752_pm_ops = {
.suspend = max96752_pm_suspend,
.resume = max96752_pm_resume,
};
static int max96752_irq_lock_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static int max96752_irq_err_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static struct serdes_chip_irq_ops max96752_irq_ops = {
.lock_handle = max96752_irq_lock_handle,
.err_handle = max96752_irq_err_handle,
};
struct serdes_chip_data serdes_max96752_data = {
.name = "max96752",
.serdes_type = TYPE_DES,
.serdes_id = MAXIM_ID_MAX96752,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
.regmap_config = &max96752_regmap_config,
.pinctrl_info = &max96752_pinctrl_info,
.panel_ops = &max96752_panel_ops,
.pinctrl_ops = &max96752_pinctrl_ops,
.gpio_ops = &max96752_gpio_ops,
.pm_ops = &max96752_pm_ops,
.irq_ops = &max96752_irq_ops,
};
EXPORT_SYMBOL_GPL(serdes_max96752_data);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* maxim-max96752.h -- register define for max96752 chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author:
*
*/
#ifndef __MFD_SERDES_MAXIM_MAX96752_H__
#define __MFD_SERDES_MAXIM_MAX96752_H__
#endif

View File

@@ -0,0 +1,719 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* maxim-max96755.c -- I2C register interface access for max96755 serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author:
*/
#include "../core.h"
#include "maxim-max96755.h"
static bool max96755_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case 0x0002:
case 0x0010:
case 0x0013:
case 0x0053:
case 0x0057:
case 0x02be ... 0x02fc:
case 0x0311:
case 0x032a:
case 0x0330 ... 0x0331:
case 0x0385 ... 0x0387:
case 0x03a4 ... 0x03ae:
return false;
default:
return true;
}
}
static struct regmap_config max96755_regmap_config = {
.name = "max96755",
.reg_bits = 16,
.val_bits = 8,
.max_register = 0x8000,
.volatile_reg = max96755_volatile_reg,
.cache_type = REGCACHE_RBTREE,
};
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;
};
struct config_desc {
u16 reg;
u8 mask;
u8 val;
};
struct serdes_group_data {
const struct config_desc *configs;
int num_configs;
};
static int MAX96755_MFP0_pins[] = {0};
static int MAX96755_MFP1_pins[] = {1};
static int MAX96755_MFP2_pins[] = {2};
static int MAX96755_MFP3_pins[] = {3};
static int MAX96755_MFP4_pins[] = {4};
static int MAX96755_MFP5_pins[] = {5};
static int MAX96755_MFP6_pins[] = {6};
static int MAX96755_MFP7_pins[] = {7};
static int MAX96755_MFP8_pins[] = {8};
static int MAX96755_MFP9_pins[] = {9};
static int MAX96755_MFP10_pins[] = {10};
static int MAX96755_MFP11_pins[] = {11};
static int MAX96755_MFP12_pins[] = {12};
static int MAX96755_MFP13_pins[] = {13};
static int MAX96755_MFP14_pins[] = {14};
static int MAX96755_MFP15_pins[] = {15};
static int MAX96755_MFP16_pins[] = {16};
static int MAX96755_MFP17_pins[] = {17};
static int MAX96755_MFP18_pins[] = {18};
static int MAX96755_MFP19_pins[] = {19};
static int MAX96755_MFP20_pins[] = {20};
static int MAX96755_I2C_pins[] = {19, 20};
static int MAX96755_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 MAX96755_MFP0_configs[] = {
{ 0x0005, LOCK_EN, 0 },
{ 0x0048, LOC_MS_EN, 0 },
};
static const struct config_desc MAX96755_MFP1_configs[] = {
{ 0x0005, ERRB_EN, 0 },
};
static const struct config_desc MAX96755_MFP4_configs[] = {
{ 0x070, SPI_EN, 0 },
};
static const struct config_desc MAX96755_MFP5_configs[] = {
{ 0x006, RCLKEN, 0 },
};
static const struct config_desc MAX96755_MFP7_configs[] = {
{ 0x0002, AUD_TX_EN_X, 0 },
{ 0x0002, AUD_TX_EN_Y, 0 }
};
static const struct config_desc MAX96755_MFP8_configs[] = {
{ 0x0002, AUD_TX_EN_X, 0 },
{ 0x0002, AUD_TX_EN_Y, 0 }
};
static const struct config_desc MAX96755_MFP9_configs[] = {
{ 0x0002, AUD_TX_EN_X, 0 },
{ 0x0002, AUD_TX_EN_Y, 0 }
};
static const struct config_desc MAX96755_MFP10_configs[] = {
{ 0x0001, IIC_2_EN, 0 },
{ 0x0003, UART_2_EN, 0 },
{ 0x0140, AUD_RX_EN, 0 },
};
static const struct config_desc MAX96755_MFP11_configs[] = {
{ 0x0001, IIC_2_EN, 0 },
{ 0x0003, UART_2_EN, 0 },
{ 0x0140, AUD_RX_EN, 0 },
};
static const struct config_desc MAX96755_MFP12_configs[] = {
{ 0x0140, AUD_RX_EN, 0 },
};
static const struct config_desc MAX96755_MFP13_configs[] = {
{ 0x0005, PU_LF0, 0 },
};
static const struct config_desc MAX96755_MFP14_configs[] = {
{ 0x0005, PU_LF1, 0 },
};
static const struct config_desc MAX96755_MFP15_configs[] = {
{ 0x0005, PU_LF2, 0 },
};
static const struct config_desc MAX96755_MFP16_configs[] = {
{ 0x0005, PU_LF3, 0 },
};
static const struct config_desc MAX96755_MFP17_configs[] = {
{ 0x0001, IIC_1_EN, 0 },
{ 0x0003, UART_1_EN, 0 },
};
static const struct config_desc MAX96755_MFP18_configs[] = {
{ 0x0001, IIC_1_EN, 0 },
{ 0x0003, UART_1_EN, 0 },
};
static const char *serdes_gpio_groups[] = {
"MAX96755_MFP0", "MAX96755_MFP1", "MAX96755_MFP2", "MAX96755_MFP3",
"MAX96755_MFP4", "MAX96755_MFP5", "MAX96755_MFP6", "MAX96755_MFP7",
"MAX96755_MFP8", "MAX96755_MFP9", "MAX96755_MFP10", "MAX96755_MFP11",
"MAX96755_MFP12", "MAX96755_MFP13", "MAX96755_MFP14", "MAX96755_MFP15",
"MAX96755_MFP16", "MAX96755_MFP17", "MAX96755_MFP18", "MAX96755_MFP19",
"MAX96755_MFP20",
};
static const char *MAX96755_I2C_groups[] = { "MAX96755_I2C" };
static const char *MAX96755_UART_groups[] = { "MAX96755_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_GPIO"#id"_INPUT", \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
.data = (void *)(const struct serdes_function_data []) { \
{ .gpio_rx_en = 1, .gpio_rx_id = id } \
}, \
} \
#define FUNCTION_DESC_GPIO_OUTPUT(id) \
{ \
.name = "DES_GPIO"#id"_OUTPUT", \
.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 max96755_pins_desc[] = {
PINCTRL_PIN(MAXIM_MAX96755_MFP0, "MAX96755_MFP0"),
PINCTRL_PIN(MAXIM_MAX96755_MFP1, "MAX96755_MFP1"),
PINCTRL_PIN(MAXIM_MAX96755_MFP2, "MAX96755_MFP2"),
PINCTRL_PIN(MAXIM_MAX96755_MFP3, "MAX96755_MFP3"),
PINCTRL_PIN(MAXIM_MAX96755_MFP4, "MAX96755_MFP4"),
PINCTRL_PIN(MAXIM_MAX96755_MFP5, "MAX96755_MFP5"),
PINCTRL_PIN(MAXIM_MAX96755_MFP6, "MAX96755_MFP6"),
PINCTRL_PIN(MAXIM_MAX96755_MFP7, "MAX96755_MFP7"),
PINCTRL_PIN(MAXIM_MAX96755_MFP8, "MAX96755_MFP8"),
PINCTRL_PIN(MAXIM_MAX96755_MFP9, "MAX96755_MFP9"),
PINCTRL_PIN(MAXIM_MAX96755_MFP10, "MAX96755_MFP10"),
PINCTRL_PIN(MAXIM_MAX96755_MFP11, "MAX96755_MFP11"),
PINCTRL_PIN(MAXIM_MAX96755_MFP12, "MAX96755_MFP12"),
PINCTRL_PIN(MAXIM_MAX96755_MFP13, "MAX96755_MFP13"),
PINCTRL_PIN(MAXIM_MAX96755_MFP14, "MAX96755_MFP14"),
PINCTRL_PIN(MAXIM_MAX96755_MFP15, "MAX96755_MFP15"),
PINCTRL_PIN(MAXIM_MAX96755_MFP16, "MAX96755_MFP16"),
PINCTRL_PIN(MAXIM_MAX96755_MFP17, "MAX96755_MFP17"),
PINCTRL_PIN(MAXIM_MAX96755_MFP18, "MAX96755_MFP18"),
PINCTRL_PIN(MAXIM_MAX96755_MFP19, "MAX96755_MFP19"),
PINCTRL_PIN(MAXIM_MAX96755_MFP20, "MAX96755_MFP20"),
};
static struct group_desc max96755_groups_desc[] = {
GROUP_DESC_CONFIG(MAX96755_MFP0),
GROUP_DESC_CONFIG(MAX96755_MFP1),
GROUP_DESC(MAX96755_MFP2),
GROUP_DESC(MAX96755_MFP3),
GROUP_DESC_CONFIG(MAX96755_MFP4),
GROUP_DESC_CONFIG(MAX96755_MFP5),
GROUP_DESC(MAX96755_MFP6),
GROUP_DESC_CONFIG(MAX96755_MFP7),
GROUP_DESC_CONFIG(MAX96755_MFP8),
GROUP_DESC_CONFIG(MAX96755_MFP9),
GROUP_DESC_CONFIG(MAX96755_MFP10),
GROUP_DESC_CONFIG(MAX96755_MFP11),
GROUP_DESC_CONFIG(MAX96755_MFP12),
GROUP_DESC_CONFIG(MAX96755_MFP13),
GROUP_DESC_CONFIG(MAX96755_MFP14),
GROUP_DESC_CONFIG(MAX96755_MFP15),
GROUP_DESC_CONFIG(MAX96755_MFP16),
GROUP_DESC_CONFIG(MAX96755_MFP17),
GROUP_DESC_CONFIG(MAX96755_MFP18),
GROUP_DESC(MAX96755_MFP19),
GROUP_DESC(MAX96755_MFP20),
GROUP_DESC(MAX96755_I2C),
GROUP_DESC(MAX96755_UART),
};
static struct function_desc max96755_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(MAX96755_I2C),
FUNCTION_DESC(MAX96755_UART),
};
static struct serdes_chip_pinctrl_info max96755_pinctrl_info = {
.pins = max96755_pins_desc,
.num_pins = ARRAY_SIZE(max96755_pins_desc),
.groups = max96755_groups_desc,
.num_groups = ARRAY_SIZE(max96755_groups_desc),
.functions = max96755_functions_desc,
.num_functions = ARRAY_SIZE(max96755_functions_desc),
};
static int max96755_bridge_init(struct serdes *serdes)
{
return 0;
}
static bool max96755_bridge_link_locked(struct serdes *serdes)
{
u32 val;
if (serdes->lock_gpio)
return gpiod_get_value_cansleep(serdes->lock_gpio);
if (serdes_reg_read(serdes, 0x0013, &val))
return false;
if (!FIELD_GET(LOCKED, val))
return false;
return true;
}
static int max96755_bridge_attach(struct serdes *serdes)
{
if (max96755_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
max96755_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 (!max96755_bridge_link_locked(serdes)) {
status = connector_status_disconnected;
goto out;
}
if (extcon_get_state(serdes->extcon, EXTCON_JACK_VIDEO_OUT)) {
if (atomic_cmpxchg(&serdes_bridge->triggered, 1, 0)) {
status = connector_status_disconnected;
goto out;
}
} else {
atomic_set(&serdes_bridge->triggered, 0);
}
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_MFD("%s: status=%d\n", __func__, status);
return status;
}
static int max96755_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 max96755_bridge_disable(struct serdes *serdes)
{
int ret = 0;
return ret;
}
static struct serdes_chip_bridge_ops max96755_bridge_ops = {
.init = max96755_bridge_init,
.attach = max96755_bridge_attach,
.detect = max96755_bridge_detect,
.enable = max96755_bridge_enable,
.disable = max96755_bridge_disable,
};
static int max96755_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 *fdata = 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 | 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(grp->pins[i] - pinctrl->pin_base),
GPIO_TX_ID,
FIELD_PREP(GPIO_TX_ID, fdata->gpio_tx_id));
if (fdata->gpio_rx_en)
serdes_set_bits(serdes,
GPIO_C_REG(grp->pins[i] - pinctrl->pin_base),
GPIO_RX_ID,
FIELD_PREP(GPIO_RX_ID, fdata->gpio_rx_id));
}
}
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 max96755_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 max96755_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 max96755_pinctrl_ops = {
.pin_config_get = max96755_pinctrl_config_get,
.pin_config_set = max96755_pinctrl_config_set,
.set_mux = max96755_pinctrl_set_mux,
};
static int max96755_gpio_direction_input(struct serdes *serdes, int gpio)
{
return 0;
}
static int max96755_gpio_direction_output(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int max96755_gpio_get_level(struct serdes *serdes, int gpio)
{
return 0;
}
static int max96755_gpio_set_level(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int max96755_gpio_set_config(struct serdes *serdes, int gpio, unsigned long config)
{
return 0;
}
static int max96755_gpio_to_irq(struct serdes *serdes, int gpio)
{
return 0;
}
static struct serdes_chip_gpio_ops max96755_gpio_ops = {
.direction_input = max96755_gpio_direction_input,
.direction_output = max96755_gpio_direction_output,
.get_level = max96755_gpio_get_level,
.set_level = max96755_gpio_set_level,
.set_config = max96755_gpio_set_config,
.to_irq = max96755_gpio_to_irq,
};
static int max96755_pm_suspend(struct serdes *serdes)
{
return 0;
}
static int max96755_pm_resume(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_pm_ops max96755_pm_ops = {
.suspend = max96755_pm_suspend,
.resume = max96755_pm_resume,
};
static int max96755_irq_lock_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static int max96755_irq_err_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static struct serdes_chip_irq_ops max96755_irq_ops = {
.lock_handle = max96755_irq_lock_handle,
.err_handle = max96755_irq_err_handle,
};
struct serdes_chip_data serdes_max96755_data = {
.name = "max96755",
.serdes_type = TYPE_SER,
.serdes_id = MAXIM_ID_MAX96755,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
.regmap_config = &max96755_regmap_config,
.pinctrl_info = &max96755_pinctrl_info,
.bridge_ops = &max96755_bridge_ops,
.pinctrl_ops = &max96755_pinctrl_ops,
.gpio_ops = &max96755_gpio_ops,
.pm_ops = &max96755_pm_ops,
.irq_ops = &max96755_irq_ops,
};
EXPORT_SYMBOL_GPL(serdes_max96755_data);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,189 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* maxim-max96755.h -- register define for max96755 chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author:
*
*/
#ifndef __MFD_SERDES_MAXIM_MAX96755_H__
#define __MFD_SERDES_MAXIM_MAX96755_H__
#include <linux/bitfield.h>
#define GPIO_A_REG(gpio) (0x02be + ((gpio) * 3))
#define GPIO_B_REG(gpio) (0x02bf + ((gpio) * 3))
#define GPIO_C_REG(gpio) (0x02c0 + ((gpio) * 3))
/* 0000h */
#define DEV_ADDR GENMASK(7, 1)
#define CFG_BLOCK BIT(0)
/* 0001h */
#define IIC_2_EN BIT(7)
#define IIC_1_EN BIT(6)
#define DIS_REM_CC BIT(4)
#define TX_RATE GENMASK(3, 2)
/* 0002h */
#define VID_TX_EN_U BIT(7)
#define VID_TX_EN_Z BIT(6)
#define VID_TX_EN_Y BIT(5)
#define VID_TX_EN_X BIT(4)
#define AUD_TX_EN_Y BIT(3)
#define AUD_TX_EN_X BIT(2)
/* 0003h */
#define UART_2_EN BIT(5)
#define UART_1_EN BIT(4)
/* 0005h */
#define LOCK_EN BIT(7)
#define ERRB_EN BIT(6)
#define PU_LF3 BIT(3)
#define PU_LF2 BIT(2)
#define PU_LF1 BIT(1)
#define PU_LF0 BIT(0)
/* 0006h */
#define RCLKEN BIT(5)
/* 0010h */
#define RESET_ALL BIT(7)
#define RESET_LINK BIT(6)
#define RESET_ONESHOT BIT(5)
#define AUTO_LINK BIT(4)
#define SLEEP BIT(3)
#define REG_ENABLE BIT(2)
#define LINK_CFG GENMASK(1, 0)
/* 0013h */
#define LINK_MODE GENMASK(5, 4)
#define LOCKED BIT(3)
/* 0026h */
#define LF_1 GENMASK(6, 4)
#define LF_0 GENMASK(2, 0)
/* 0048h */
#define REM_MS_EN BIT(5)
#define LOC_MS_EN BIT(4)
/* 0053h */
#define TX_SPLIT_MASK_B BIT(5)
#define TX_SPLIT_MASK_A BIT(4)
#define TX_STR_SEL GENMASK(1, 0)
/* 0140h */
#define AUD_RX_EN BIT(0)
/* 0170h */
#define SPI_EN BIT(0)
/* 01e5h */
#define PATGEN_MODE GENMASK(1, 0)
/* 02beh */
#define RES_CFG BIT(7)
#define TX_PRIO BIT(6)
#define TX_COMP_EN BIT(5)
#define GPIO_OUT BIT(4)
#define GPIO_IN BIT(3)
#define GPIO_RX_EN BIT(2)
#define GPIO_TX_EN BIT(1)
#define GPIO_OUT_DIS BIT(0)
/* 02bfh */
#define PULL_UPDN_SEL GENMASK(7, 6)
#define OUT_TYPE BIT(5)
#define GPIO_TX_ID GENMASK(4, 0)
/* 02c0h */
#define OVR_RES_CFG BIT(7)
#define GPIO_RX_ID GENMASK(4, 0)
/* 0311h */
#define START_PORTBU BIT(7)
#define START_PORTBZ BIT(6)
#define START_PORTBY BIT(5)
#define START_PORTBX BIT(4)
#define START_PORTAU BIT(3)
#define START_PORTAZ BIT(2)
#define START_PORTAY BIT(1)
#define START_PORTAX BIT(0)
/* 032ah */
#define DV_LOCK BIT(7)
#define DV_SWP_AB BIT(6)
#define LINE_ALT BIT(5)
#define DV_CONV BIT(2)
#define DV_SPL BIT(1)
#define DV_EN BIT(0)
/* 0330h */
#define PHY_CONFIG GENMASK(2, 0)
#define MIPI_RX_RESET BIT(3)
/* 0331h */
#define NUM_LANES GENMASK(1, 0)
/* 0385h */
#define DPI_HSYNC_WIDTH_L GENMASK(7, 0)
/* 0386h */
#define DPI_VYSNC_WIDTH_L GENMASK(7, 0)
/* 0387h */
#define DPI_HSYNC_WIDTH_H GENMASK(3, 0)
#define DPI_VSYNC_WIDTH_H GENMASK(7, 4)
/* 03a4h */
#define DPI_DE_SKEW_SEL BIT(1)
#define DPI_DESKEW_EN BIT(0)
/* 03a5h */
#define DPI_VFP_L GENMASK(7, 0)
/* 03a6h */
#define DPI_VFP_H GENMASK(3, 0)
#define DPI_VBP_L GENMASK(7, 4)
/* 03a7h */
#define DPI_VBP_H GENMASK(7, 0)
/* 03a8h */
#define DPI_VACT_L GENMASK(7, 0)
/* 03a9h */
#define DPI_VACT_H GENMASK(3, 0)
/* 03aah */
#define DPI_HFP_L GENMASK(7, 0)
/* 03abh */
#define DPI_HFP_H GENMASK(3, 0)
#define DPI_HBP_L GENMASK(7, 4)
/* 03ach */
#define DPI_HBP_H GENMASK(7, 0)
/* 03adh */
#define DPI_HACT_L GENMASK(7, 0)
/* 03aeh */
#define DPI_HACT_H GENMASK(4, 0)
/* 055dh */
#define VS_DET BIT(5)
#define HS_DET BIT(4)
enum link_mode {
DUAL_LINK,
LINKA,
LINKB,
SPLITTER_MODE,
};
#endif

View File

@@ -0,0 +1,328 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* maxim-max96772.c -- I2C register interface access for max96772 serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author:
*/
#include "../core.h"
#include "maxim-max96772.h"
static const struct regmap_range max96772_readable_ranges[] = {
regmap_reg_range(0x0000, 0x0800),
regmap_reg_range(0x1700, 0x1700),
regmap_reg_range(0x4100, 0x4100),
regmap_reg_range(0x6230, 0x6230),
regmap_reg_range(0xe75e, 0xe75e),
regmap_reg_range(0xe776, 0xe7bf),
};
static const struct regmap_access_table max96772_readable_table = {
.yes_ranges = max96772_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(max96772_readable_ranges),
};
static struct regmap_config max96772_regmap_config = {
.name = "max96772",
.reg_bits = 16,
.val_bits = 8,
.max_register = 0xffff,
.rd_table = &max96772_readable_table,
};
static int MAX96772_MFP0_pins[] = {0};
static int MAX96772_MFP1_pins[] = {1};
static int MAX96772_MFP2_pins[] = {2};
static int MAX96772_MFP3_pins[] = {3};
static int MAX96772_MFP4_pins[] = {4};
static int MAX96772_MFP5_pins[] = {5};
static int MAX96772_MFP6_pins[] = {6};
static int MAX96772_MFP7_pins[] = {7};
static int MAX96772_MFP8_pins[] = {8};
static int MAX96772_MFP9_pins[] = {9};
static int MAX96772_MFP10_pins[] = {10};
static int MAX96772_MFP11_pins[] = {11};
static int MAX96772_MFP12_pins[] = {12};
static int MAX96772_MFP13_pins[] = {13};
static int MAX96772_MFP14_pins[] = {14};
static int MAX96772_MFP15_pins[] = {15};
#define GROUP_DESC(nm) \
{ \
.name = #nm, \
.pins = nm ## _pins, \
.num_pins = ARRAY_SIZE(nm ## _pins), \
}
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;
};
static const char *serdes_gpio_groups[] = {
"MAX96772_MFP0", "MAX96772_MFP1", "MAX96772_MFP2", "MAX96772_MFP3",
"MAX96772_MFP4", "MAX96772_MFP5", "MAX96772_MFP6", "MAX96772_MFP7",
"MAX96772_MFP8", "MAX96772_MFP9", "MAX96772_MFP10", "MAX96772_MFP11",
"MAX96772_MFP12", "MAX96772_MFP13", "MAX96772_MFP14", "MAX96772_MFP15",
};
#define FUNCTION_DESC_GPIO_INPUT(id) \
{ \
.name = "MFP"#id"_INPUT", \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
.data = (void *)(const struct serdes_function_data []) { \
{ .gpio_rx_en = 1, .gpio_rx_id = id } \
}, \
} \
#define FUNCTION_DESC_GPIO_OUTPUT(id) \
{ \
.name = "MFP"#id"_OUTPUT", \
.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 max96772_pins_desc[] = {
PINCTRL_PIN(MAXIM_MAX96772_MFP0, "MAX96772_MFP0"),
PINCTRL_PIN(MAXIM_MAX96772_MFP1, "MAX96772_MFP1"),
PINCTRL_PIN(MAXIM_MAX96772_MFP2, "MAX96772_MFP2"),
PINCTRL_PIN(MAXIM_MAX96772_MFP3, "MAX96772_MFP3"),
PINCTRL_PIN(MAXIM_MAX96772_MFP4, "MAX96772_MFP4"),
PINCTRL_PIN(MAXIM_MAX96772_MFP5, "MAX96772_MFP5"),
PINCTRL_PIN(MAXIM_MAX96772_MFP6, "MAX96772_MFP6"),
PINCTRL_PIN(MAXIM_MAX96772_MFP7, "MAX96772_MFP7"),
PINCTRL_PIN(MAXIM_MAX96772_MFP8, "MAX96772_MFP8"),
PINCTRL_PIN(MAXIM_MAX96772_MFP9, "MAX96772_MFP9"),
PINCTRL_PIN(MAXIM_MAX96772_MFP10, "MAX96772_MFP10"),
PINCTRL_PIN(MAXIM_MAX96772_MFP11, "MAX96772_MFP11"),
PINCTRL_PIN(MAXIM_MAX96772_MFP12, "MAX96772_MFP12"),
PINCTRL_PIN(MAXIM_MAX96772_MFP13, "MAX96772_MFP13"),
PINCTRL_PIN(MAXIM_MAX96772_MFP14, "MAX96772_MFP14"),
PINCTRL_PIN(MAXIM_MAX96772_MFP15, "MAX96772_MFP15"),
};
static struct group_desc max96772_groups_desc[] = {
GROUP_DESC(MAX96772_MFP0),
GROUP_DESC(MAX96772_MFP1),
GROUP_DESC(MAX96772_MFP2),
GROUP_DESC(MAX96772_MFP3),
GROUP_DESC(MAX96772_MFP4),
GROUP_DESC(MAX96772_MFP5),
GROUP_DESC(MAX96772_MFP6),
GROUP_DESC(MAX96772_MFP7),
GROUP_DESC(MAX96772_MFP8),
GROUP_DESC(MAX96772_MFP9),
GROUP_DESC(MAX96772_MFP10),
GROUP_DESC(MAX96772_MFP11),
GROUP_DESC(MAX96772_MFP12),
GROUP_DESC(MAX96772_MFP13),
GROUP_DESC(MAX96772_MFP14),
GROUP_DESC(MAX96772_MFP15),
};
static struct function_desc max96772_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_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),
};
static struct serdes_chip_pinctrl_info max96772_pinctrl_info = {
.pins = max96772_pins_desc,
.num_pins = ARRAY_SIZE(max96772_pins_desc),
.groups = max96772_groups_desc,
.num_groups = ARRAY_SIZE(max96772_groups_desc),
.functions = max96772_functions_desc,
.num_functions = ARRAY_SIZE(max96772_functions_desc),
};
static int max96772_panel_init(struct serdes *serdes)
{
return 0;
}
static int max96772_panel_prepare(struct serdes *serdes)
{
return 0;
}
static int max96772_panel_unprepare(struct serdes *serdes)
{
return 0;
}
static int max96772_panel_enable(struct serdes *serdes)
{
return 0;
}
static int max96772_panel_disable(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_panel_ops max96772_panel_ops = {
.init = max96772_panel_init,
.prepare = max96772_panel_prepare,
.unprepare = max96772_panel_unprepare,
.enable = max96772_panel_enable,
.disable = max96772_panel_disable,
};
static int max96772_pinctrl_config_get(struct serdes *serdes,
unsigned int pin,
unsigned long *config)
{
return 0;
}
static int max96772_pinctrl_config_set(struct serdes *serdes,
unsigned int pin,
unsigned long *configs,
unsigned int num_configs)
{
return 0;
}
static int max96772_pinctrl_set_mux(struct serdes *serdes, unsigned int func_selector,
unsigned int group_selector)
{
return 0;
}
static struct serdes_chip_pinctrl_ops max96772_pinctrl_ops = {
.pin_config_get = max96772_pinctrl_config_get,
.pin_config_set = max96772_pinctrl_config_set,
.set_mux = max96772_pinctrl_set_mux,
};
static int max96772_gpio_direction_input(struct serdes *serdes, int gpio)
{
return 0;
}
static int max96772_gpio_direction_output(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int max96772_gpio_get_level(struct serdes *serdes, int gpio)
{
return 0;
}
static int max96772_gpio_set_level(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int max96772_gpio_set_config(struct serdes *serdes, int gpio, unsigned long config)
{
return 0;
}
static int max96772_gpio_to_irq(struct serdes *serdes, int gpio)
{
return 0;
}
static struct serdes_chip_gpio_ops max96772_gpio_ops = {
.direction_input = max96772_gpio_direction_input,
.direction_output = max96772_gpio_direction_output,
.get_level = max96772_gpio_get_level,
.set_level = max96772_gpio_set_level,
.set_config = max96772_gpio_set_config,
.to_irq = max96772_gpio_to_irq,
};
static int max96772_pm_suspend(struct serdes *serdes)
{
return 0;
}
static int max96772_pm_resume(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_pm_ops max96772_pm_ops = {
.suspend = max96772_pm_suspend,
.resume = max96772_pm_resume,
};
static int max96772_irq_lock_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static int max96772_irq_err_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static struct serdes_chip_irq_ops max96772_irq_ops = {
.lock_handle = max96772_irq_lock_handle,
.err_handle = max96772_irq_err_handle,
};
struct serdes_chip_data serdes_max96772_data = {
.name = "max96772",
.serdes_type = TYPE_DES,
.serdes_id = MAXIM_ID_MAX96772,
.connector_type = DRM_MODE_CONNECTOR_eDP,
.regmap_config = &max96772_regmap_config,
.pinctrl_info = &max96772_pinctrl_info,
.panel_ops = &max96772_panel_ops,
.pinctrl_ops = &max96772_pinctrl_ops,
.gpio_ops = &max96772_gpio_ops,
.pm_ops = &max96772_pm_ops,
.irq_ops = &max96772_irq_ops,
};
EXPORT_SYMBOL_GPL(serdes_max96772_data);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* include/linux/mfd/serdes/gpio.h -- GPIO for different serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*
*/
#ifndef __MFD_SERDES_MAXIM_MAX96772_H__
#define __MFD_SERDES_MAXIM_MAX96772_H__
#endif

View File

@@ -0,0 +1,352 @@
// 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:
*/
#include "../core.h"
#include "maxim-max96789.h"
static bool max96789_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 max96789_regmap_config = {
.name = "max96789",
.reg_bits = 16,
.val_bits = 8,
.max_register = 0x8000,
.volatile_reg = max96789_volatile_reg,
.cache_type = REGCACHE_RBTREE,
};
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};
#define GROUP_DESC(nm) \
{ \
.name = #nm, \
.pins = nm ## _pins, \
.num_pins = ARRAY_SIZE(nm ## _pins), \
}
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;
};
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",
};
#define FUNCTION_DESC_GPIO_INPUT(id) \
{ \
.name = "DES_GPIO"#id"_INPUT", \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
.data = (void *)(const struct serdes_function_data []) { \
{ .gpio_rx_en = 1, .gpio_rx_id = id } \
}, \
} \
#define FUNCTION_DESC_GPIO_OUTPUT(id) \
{ \
.name = "DES_GPIO"#id"_OUTPUT", \
.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(MAX96789_MFP0),
GROUP_DESC(MAX96789_MFP1),
GROUP_DESC(MAX96789_MFP2),
GROUP_DESC(MAX96789_MFP3),
GROUP_DESC(MAX96789_MFP4),
GROUP_DESC(MAX96789_MFP5),
GROUP_DESC(MAX96789_MFP6),
GROUP_DESC(MAX96789_MFP7),
GROUP_DESC(MAX96789_MFP8),
GROUP_DESC(MAX96789_MFP9),
GROUP_DESC(MAX96789_MFP10),
GROUP_DESC(MAX96789_MFP11),
GROUP_DESC(MAX96789_MFP12),
GROUP_DESC(MAX96789_MFP13),
GROUP_DESC(MAX96789_MFP14),
GROUP_DESC(MAX96789_MFP15),
GROUP_DESC(MAX96789_MFP16),
GROUP_DESC(MAX96789_MFP17),
GROUP_DESC(MAX96789_MFP18),
GROUP_DESC(MAX96789_MFP19),
GROUP_DESC(MAX96789_MFP20),
};
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),
};
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 int max96789_bridge_init(struct serdes *serdes)
{
return 0;
}
static int max96789_bridge_enable(struct serdes *serdes)
{
return 0;
}
static int max96789_bridge_disable(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_bridge_ops max96789_bridge_ops = {
.init = max96789_bridge_init,
.enable = max96789_bridge_enable,
.disable = max96789_bridge_disable,
};
static int max96789_pinctrl_config_get(struct serdes *serdes,
unsigned int pin,
unsigned long *config)
{
return 0;
}
static int max96789_pinctrl_config_set(struct serdes *serdes,
unsigned int pin,
unsigned long *configs,
unsigned int num_configs)
{
return 0;
}
static int max96789_pinctrl_set_mux(struct serdes *serdes, unsigned int func_selector,
unsigned int group_selector)
{
return 0;
}
static struct serdes_chip_pinctrl_ops max96789_pinctrl_ops = {
.pin_config_get = max96789_pinctrl_config_get,
.pin_config_set = max96789_pinctrl_config_set,
.set_mux = max96789_pinctrl_set_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_pm_suspend(struct serdes *serdes)
{
return 0;
}
static int max96789_pm_resume(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_pm_ops max96789_pm_ops = {
.suspend = max96789_pm_suspend,
.resume = max96789_pm_resume,
};
static int max96789_irq_lock_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static int max96789_irq_err_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static struct serdes_chip_irq_ops max96789_irq_ops = {
.lock_handle = max96789_irq_lock_handle,
.err_handle = max96789_irq_err_handle,
};
struct serdes_chip_data serdes_max96789_data = {
.name = "max96789",
.serdes_type = TYPE_SER,
.serdes_id = MAXIM_ID_MAX96789,
.connector_type = DRM_MODE_CONNECTOR_DSI,
.regmap_config = &max96789_regmap_config,
.pinctrl_info = &max96789_pinctrl_info,
.bridge_ops = &max96789_bridge_ops,
.pinctrl_ops = &max96789_pinctrl_ops,
.gpio_ops = &max96789_gpio_ops,
.pm_ops = &max96789_pm_ops,
.irq_ops = &max96789_irq_ops,
};
EXPORT_SYMBOL_GPL(serdes_max96789_data);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* maxim-max96789.h -- register define for max96789 chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author:
*
*/
#ifndef __MFD_SERDES_MAXIM_MAX96789_H__
#define __MFD_SERDES_MAXIM_MAX96789_H__
#endif

View File

@@ -0,0 +1,20 @@
# SPDX-License-Identifier: GPL-2.0
#
# rohm serdes drivers configuration
#
menuconfig SERDES_DISPLAY_CHIP_NOVO
tristate "novo expander device support"
default y
help
Enable this to be able to choose the drivers for controlling the
rohm serdes.
if SERDES_DISPLAY_CHIP_NOVO
config SERDES_DISPLAY_CHIP_NOVO_NCA9539
tristate "novo nca9539 expander"
default y
help
To support novo nca9539 expander.
endif

View File

@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
#
# novo display serdes drivers configuration
#
obj-$(CONFIG_SERDES_DISPLAY_CHIP_NOVO_NCA9539) += novo-nca9539.o

View File

@@ -0,0 +1,370 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* maxim-nca9539.c -- I2C register interface access for nca9539 chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "../core.h"
#define REG_NCA9539_INPUT_PORT0 0x00 //Read only default 1111 1111
#define REG_NCA9539_INPUT_PORT1 0x01 //Read only default 1111 1111
#define REG_NCA9539_OUT_LEVEL_PORT0 0x02 //Read/write default 1111 1111
#define REG_NCA9539_OUT_LEVEL_PORT1 0x03 //Read/write default 1111 1111
#define REG_NCA9539_INVER_PORT0 0x04 //Read/write default 0000 0000
#define REG_NCA9539_INVER_PORT1 0x05 //Read/write default 0000 0000
#define REG_NCA9539_DIR_PORT0 0x06 //Read/write byte 1111 1111
#define REG_NCA9539_DIR_PORT1 0x07 //Read/write byte 1111 1111
static bool nca9539_volatile_reg(struct device *dev, unsigned int reg)
{
return true;
}
static struct regmap_config nca9539_regmap_config = {
.name = "nca9539",
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x0007,
.volatile_reg = nca9539_volatile_reg,
.cache_type = REGCACHE_RBTREE,
};
static int NCA9539_GPIO0_pins[] = {0};
static int NCA9539_GPIO1_pins[] = {1};
static int NCA9539_GPIO2_pins[] = {2};
static int NCA9539_GPIO3_pins[] = {3};
static int NCA9539_GPIO4_pins[] = {4};
static int NCA9539_GPIO5_pins[] = {5};
static int NCA9539_GPIO6_pins[] = {6};
static int NCA9539_GPIO7_pins[] = {7};
static int NCA9539_GPIO8_pins[] = {8};
static int NCA9539_GPIO9_pins[] = {9};
static int NCA9539_GPIO10_pins[] = {10};
static int NCA9539_GPIO11_pins[] = {11};
static int NCA9539_GPIO12_pins[] = {12};
static int NCA9539_GPIO13_pins[] = {13};
static int NCA9539_GPIO14_pins[] = {14};
static int NCA9539_GPIO15_pins[] = {15};
#define GROUP_DESC(nm) \
{ \
.name = #nm, \
.pins = nm ## _pins, \
.num_pins = ARRAY_SIZE(nm ## _pins), \
}
static const char *serdes_gpio_groups[] = {
"NCA9539_GPIO0", "NCA9539_GPIO1", "NCA9539_GPIO2", "NCA9539_GPIO3",
"NCA9539_GPIO4", "NCA9539_GPIO5", "NCA9539_GPIO6", "NCA9539_GPIO7",
"NCA9539_GPIO8", "NCA9539_GPIO9", "NCA9539_GPIO10", "NCA9539_GPIO11",
"NCA9539_GPIO12", "NCA9539_GPIO13", "NCA9539_GPIO14", "NCA9539_GPIO15",
};
/*des -> ser -> soc*/
#define FUNCTION_DESC_GPIO_INPUT(id) \
{ \
.name = "GPIO"#id"_INPUT", \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
} \
/*soc -> ser -> des*/
#define FUNCTION_DESC_GPIO_OUTPUT(id) \
{ \
.name = "GPIO"#id"_OUTPUT", \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
} \
static struct pinctrl_pin_desc nca9539_pins_desc[] = {
PINCTRL_PIN(NOVO_NCA9539_GPIO0, "NCA9539_GPIO0"),
PINCTRL_PIN(NOVO_NCA9539_GPIO1, "NCA9539_GPIO1"),
PINCTRL_PIN(NOVO_NCA9539_GPIO2, "NCA9539_GPIO2"),
PINCTRL_PIN(NOVO_NCA9539_GPIO3, "NCA9539_GPIO3"),
PINCTRL_PIN(NOVO_NCA9539_GPIO4, "NCA9539_GPIO4"),
PINCTRL_PIN(NOVO_NCA9539_GPIO5, "NCA9539_GPIO5"),
PINCTRL_PIN(NOVO_NCA9539_GPIO6, "NCA9539_GPIO6"),
PINCTRL_PIN(NOVO_NCA9539_GPIO7, "NCA9539_GPIO7"),
PINCTRL_PIN(NOVO_NCA9539_GPIO8, "NCA9539_GPIO8"),
PINCTRL_PIN(NOVO_NCA9539_GPIO9, "NCA9539_GPIO9"),
PINCTRL_PIN(NOVO_NCA9539_GPIO10, "NCA9539_GPIO10"),
PINCTRL_PIN(NOVO_NCA9539_GPIO11, "NCA9539_GPIO11"),
PINCTRL_PIN(NOVO_NCA9539_GPIO12, "NCA9539_GPIO12"),
PINCTRL_PIN(NOVO_NCA9539_GPIO13, "NCA9539_GPIO13"),
PINCTRL_PIN(NOVO_NCA9539_GPIO14, "NCA9539_GPIO14"),
PINCTRL_PIN(NOVO_NCA9539_GPIO15, "NCA9539_GPIO15"),
};
static struct group_desc nca9539_groups_desc[] = {
GROUP_DESC(NCA9539_GPIO0),
GROUP_DESC(NCA9539_GPIO1),
GROUP_DESC(NCA9539_GPIO2),
GROUP_DESC(NCA9539_GPIO3),
GROUP_DESC(NCA9539_GPIO4),
GROUP_DESC(NCA9539_GPIO5),
GROUP_DESC(NCA9539_GPIO6),
GROUP_DESC(NCA9539_GPIO7),
GROUP_DESC(NCA9539_GPIO8),
GROUP_DESC(NCA9539_GPIO9),
GROUP_DESC(NCA9539_GPIO10),
GROUP_DESC(NCA9539_GPIO11),
GROUP_DESC(NCA9539_GPIO12),
GROUP_DESC(NCA9539_GPIO13),
GROUP_DESC(NCA9539_GPIO14),
GROUP_DESC(NCA9539_GPIO15),
};
static struct function_desc nca9539_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_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),
};
static struct serdes_chip_pinctrl_info nca9539_pinctrl_info = {
.pins = nca9539_pins_desc,
.num_pins = ARRAY_SIZE(nca9539_pins_desc),
.groups = nca9539_groups_desc,
.num_groups = ARRAY_SIZE(nca9539_groups_desc),
.functions = nca9539_functions_desc,
.num_functions = ARRAY_SIZE(nca9539_functions_desc),
};
static int nca9539_pinctrl_config_get(struct serdes *serdes,
unsigned int pin, unsigned long *config)
{
return 0;
}
static int nca9539_pinctrl_config_set(struct serdes *serdes,
unsigned int pin, unsigned long *configs,
unsigned int num_configs)
{
return 0;
}
static int nca9539_pinctrl_set_mux(struct serdes *serdes,
unsigned int function, unsigned int group)
{
return 0;
}
static struct serdes_chip_pinctrl_ops nca9539_pinctrl_ops = {
.pin_config_get = nca9539_pinctrl_config_get,
.pin_config_set = nca9539_pinctrl_config_set,
.set_mux = nca9539_pinctrl_set_mux,
};
static int nca9539_gpio_direction_input(struct serdes *serdes, int gpio)
{
return 0;
}
static int nca9539_gpio_direction_output(struct serdes *serdes, int gpio, int value)
{
struct device *dev = serdes->dev;
unsigned char port, pin, dir_reg, level_reg;
int ret1 = 0, ret2 = 0;
port = (gpio / 8) & 0x01;
pin = (gpio % 8) & 0x7;
dir_reg = (port == 0) ? REG_NCA9539_DIR_PORT0 : REG_NCA9539_DIR_PORT1;
level_reg = (port == 0) ? REG_NCA9539_OUT_LEVEL_PORT0 : REG_NCA9539_OUT_LEVEL_PORT1;
switch (pin) {
case 0:
ret1 = serdes_set_bits(serdes, dir_reg, BIT(0), FIELD_PREP(BIT(0), 0));
ret2 = serdes_set_bits(serdes, level_reg, BIT(0), FIELD_PREP(BIT(0), value & 0x01));
break;
case 1:
ret1 = serdes_set_bits(serdes, dir_reg, BIT(1), FIELD_PREP(BIT(1), 0));
ret2 = serdes_set_bits(serdes, level_reg, BIT(1), FIELD_PREP(BIT(1), value & 0x01));
break;
case 2:
ret1 = serdes_set_bits(serdes, dir_reg, BIT(2), FIELD_PREP(BIT(2), 0));
ret2 = serdes_set_bits(serdes, level_reg, BIT(2), FIELD_PREP(BIT(2), value & 0x01));
break;
case 3:
ret1 = serdes_set_bits(serdes, dir_reg, BIT(3), FIELD_PREP(BIT(3), 0));
ret2 = serdes_set_bits(serdes, level_reg, BIT(3), FIELD_PREP(BIT(3), value & 0x01));
break;
case 4:
ret1 = serdes_set_bits(serdes, dir_reg, BIT(4), FIELD_PREP(BIT(4), 0));
ret2 = serdes_set_bits(serdes, level_reg, BIT(4), FIELD_PREP(BIT(4), value & 0x01));
break;
case 5:
ret1 = serdes_set_bits(serdes, dir_reg, BIT(5), FIELD_PREP(BIT(5), 0));
ret2 = serdes_set_bits(serdes, level_reg, BIT(5), FIELD_PREP(BIT(5), value & 0x01));
break;
case 6:
ret1 = serdes_set_bits(serdes, dir_reg, BIT(6), FIELD_PREP(BIT(6), 0));
ret2 = serdes_set_bits(serdes, level_reg, BIT(6), FIELD_PREP(BIT(6), value & 0x01));
break;
case 7:
ret1 = serdes_set_bits(serdes, dir_reg, BIT(7), FIELD_PREP(BIT(7), 0));
ret2 = serdes_set_bits(serdes, level_reg, BIT(7), FIELD_PREP(BIT(7), value & 0x01));
break;
default:
break;
}
if (ret1 || ret2)
dev_err(dev, "%s reg 0x%04x write error, pin=%d\n", __func__, level_reg, pin);
return 0;
}
static int nca9539_gpio_get_level(struct serdes *serdes, int gpio)
{
return 0;
}
static int nca9539_gpio_set_level(struct serdes *serdes, int gpio, int value)
{
struct device *dev = serdes->dev;
unsigned char port, pin, level_reg;
int ret = 0;
port = (gpio / 8) & 0x01;
pin = (gpio % 8) & 0x7;
level_reg = (port == 0) ? REG_NCA9539_OUT_LEVEL_PORT0 : REG_NCA9539_OUT_LEVEL_PORT1;
switch (pin) {
case 0:
ret = serdes_set_bits(serdes, level_reg, BIT(0), FIELD_PREP(BIT(0), value & 0x01));
break;
case 1:
ret = serdes_set_bits(serdes, level_reg, BIT(1), FIELD_PREP(BIT(1), value & 0x01));
break;
case 2:
ret = serdes_set_bits(serdes, level_reg, BIT(2), FIELD_PREP(BIT(2), value & 0x01));
break;
case 3:
ret = serdes_set_bits(serdes, level_reg, BIT(3), FIELD_PREP(BIT(3), value & 0x01));
break;
case 4:
ret = serdes_set_bits(serdes, level_reg, BIT(4), FIELD_PREP(BIT(4), value & 0x01));
break;
case 5:
ret = serdes_set_bits(serdes, level_reg, BIT(5), FIELD_PREP(BIT(5), value & 0x01));
break;
case 6:
ret = serdes_set_bits(serdes, level_reg, BIT(6), FIELD_PREP(BIT(6), value & 0x01));
break;
case 7:
ret = serdes_set_bits(serdes, level_reg, BIT(7), FIELD_PREP(BIT(7), value & 0x01));
break;
default:
break;
}
if (ret)
dev_err(dev, "%s reg 0x%04x write error, pin=%d\n", __func__, level_reg, pin);
SERDES_DBG_CHIP("%s: serdes chip %s gpio=%d value=%d\n",
__func__, serdes->chip_data->name, gpio, value);
return 0;
}
static int nca9539_gpio_set_config(struct serdes *serdes, int gpio, unsigned long config)
{
return 0;
}
static int nca9539_gpio_to_irq(struct serdes *serdes, int gpio)
{
return 0;
}
static struct serdes_chip_gpio_ops nca9539_gpio_ops = {
.direction_input = nca9539_gpio_direction_input,
.direction_output = nca9539_gpio_direction_output,
.get_level = nca9539_gpio_get_level,
.set_level = nca9539_gpio_set_level,
.set_config = nca9539_gpio_set_config,
.to_irq = nca9539_gpio_to_irq,
};
static int nca9539_pm_suspend(struct serdes *serdes)
{
return 0;
}
static int nca9539_pm_resume(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_pm_ops nca9539_pm_ops = {
.suspend = nca9539_pm_suspend,
.resume = nca9539_pm_resume,
};
static int nca9539_irq_lock_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static int nca9539_irq_err_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static struct serdes_chip_irq_ops nca9539_irq_ops = {
.lock_handle = nca9539_irq_lock_handle,
.err_handle = nca9539_irq_err_handle,
};
struct serdes_chip_data serdes_nca9539_data = {
.name = "nca9539",
.serdes_type = TYPE_OTHER,
.serdes_id = NOVO_ID_NCA9539,
.sequence_init = 1,
.regmap_config = &nca9539_regmap_config,
.pinctrl_info = &nca9539_pinctrl_info,
.pinctrl_ops = &nca9539_pinctrl_ops,
.gpio_ops = &nca9539_gpio_ops,
.pm_ops = &nca9539_pm_ops,
.irq_ops = &nca9539_irq_ops,
};
EXPORT_SYMBOL_GPL(serdes_nca9539_data);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,25 @@
# SPDX-License-Identifier: GPL-2.0
#
# rockchip display serdes drivers configuration
#
menuconfig SERDES_DISPLAY_CHIP_ROCKCHIP
tristate "rockchip serdes device support"
default y
help
Enable this to be able to choose the drivers for controlling the
rockchip serdes.
if SERDES_DISPLAY_CHIP_ROCKCHIP
config SERDES_DISPLAY_CHIP_ROCKCHIP_RKX111
tristate "rockchip rkx111 serdes"
default y
help
To support rockchip rkx111 display serdes.
config SERDES_DISPLAY_CHIP_ROCKCHIP_RKX121
tristate "rockchip rkx121 serdes"
default y
help
To support rockchip rkx121 display serdes.
endif

View File

@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
#
# rockchip display serdes drivers configuration
#
obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX111) += rockchip-rkx111.o
obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX121) += rockchip-rkx121.o

View File

@@ -0,0 +1,189 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* rockchip-rkx111.c -- I2C register interface access for rkx111 serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "../core.h"
static bool rkx111_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 rkx111_regmap_config = {
.name = "rkx111",
.reg_bits = 16,
.val_bits = 8,
.max_register = 0x8000,
.volatile_reg = rkx111_volatile_reg,
.cache_type = REGCACHE_RBTREE,
};
struct pinctrl_pin_desc rkx111_pins_desc[] = {
};
struct group_desc rkx111_groups_desc[] = {
{ "null", NULL, 1, },
};
struct function_desc rkx111_functions_desc[] = {
{ "null", NULL, 1, },
};
static struct serdes_chip_pinctrl_info rkx111_pinctrl_info = {
.pins = rkx111_pins_desc,
.num_pins = ARRAY_SIZE(rkx111_pins_desc),
.groups = rkx111_groups_desc,
.num_groups = ARRAY_SIZE(rkx111_groups_desc),
.functions = rkx111_functions_desc,
.num_functions = ARRAY_SIZE(rkx111_functions_desc),
};
static int rkx111_bridge_init(struct serdes *serdes)
{
return 0;
}
static int rkx111_bridge_enable(struct serdes *serdes)
{
return 0;
}
static int rkx111_bridge_disable(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_bridge_ops rkx111_bridge_ops = {
.init = rkx111_bridge_init,
.enable = rkx111_bridge_enable,
.disable = rkx111_bridge_disable,
};
static int rkx111_pinctrl_config_get(struct serdes *serdes,
unsigned int pin,
unsigned long *config)
{
return 0;
}
static int rkx111_pinctrl_config_set(struct serdes *serdes,
unsigned int pin,
unsigned long *configs,
unsigned int num_configs)
{
return 0;
}
static int rkx111_pinctrl_set_mux(struct serdes *serdes, unsigned int func_selector,
unsigned int group_selector)
{
return 0;
}
static struct serdes_chip_pinctrl_ops rkx111_pinctrl_ops = {
.pin_config_get = rkx111_pinctrl_config_get,
.pin_config_set = rkx111_pinctrl_config_set,
.set_mux = rkx111_pinctrl_set_mux,
};
static int rkx111_gpio_direction_input(struct serdes *serdes, int gpio)
{
return 0;
}
static int rkx111_gpio_direction_output(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int rkx111_gpio_get_level(struct serdes *serdes, int gpio)
{
return 0;
}
static int rkx111_gpio_set_level(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int rkx111_gpio_set_config(struct serdes *serdes, int gpio, unsigned long config)
{
return 0;
}
static int rkx111_gpio_to_irq(struct serdes *serdes, int gpio)
{
return 0;
}
static struct serdes_chip_gpio_ops rkx111_gpio_ops = {
.direction_input = rkx111_gpio_direction_input,
.direction_output = rkx111_gpio_direction_output,
.get_level = rkx111_gpio_get_level,
.set_level = rkx111_gpio_set_level,
.set_config = rkx111_gpio_set_config,
.to_irq = rkx111_gpio_to_irq,
};
static int rkx111_pm_suspend(struct serdes *serdes)
{
return 0;
}
static int rkx111_pm_resume(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_pm_ops rkx111_pm_ops = {
.suspend = rkx111_pm_suspend,
.resume = rkx111_pm_resume,
};
static int rkx111_irq_lock_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static int rkx111_irq_err_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static struct serdes_chip_irq_ops rkx111_irq_ops = {
.lock_handle = rkx111_irq_lock_handle,
.err_handle = rkx111_irq_err_handle,
};
struct serdes_chip_data serdes_rkx111_data = {
.name = "rkx111",
.serdes_type = TYPE_SER,
.serdes_id = ROCKCHIP_ID_RKX111,
.connector_type = DRM_MODE_CONNECTOR_DSI,
.regmap_config = &rkx111_regmap_config,
.pinctrl_info = &rkx111_pinctrl_info,
.bridge_ops = &rkx111_bridge_ops,
.pinctrl_ops = &rkx111_pinctrl_ops,
.gpio_ops = &rkx111_gpio_ops,
.pm_ops = &rkx111_pm_ops,
.irq_ops = &rkx111_irq_ops,
};
EXPORT_SYMBOL_GPL(serdes_rkx111_data);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,189 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* rockchip-rkx121.c -- I2C register interface access for rkx121 serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "../core.h"
static bool rkx121_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 rkx121_regmap_config = {
.name = "rkx121",
.reg_bits = 16,
.val_bits = 8,
.max_register = 0x8000,
.volatile_reg = rkx121_volatile_reg,
.cache_type = REGCACHE_RBTREE,
};
static struct pinctrl_pin_desc rkx121_pins_desc[] = {
};
static struct group_desc rkx121_groups_desc[] = {
{ "null", NULL, 1, },
};
static struct function_desc rkx121_functions_desc[] = {
{ "null", NULL, 1, },
};
static struct serdes_chip_pinctrl_info rkx121_pinctrl_info = {
.pins = rkx121_pins_desc,
.num_pins = ARRAY_SIZE(rkx121_pins_desc),
.groups = rkx121_groups_desc,
.num_groups = ARRAY_SIZE(rkx121_groups_desc),
.functions = rkx121_functions_desc,
.num_functions = ARRAY_SIZE(rkx121_functions_desc),
};
static int rkx121_bridge_init(struct serdes *serdes)
{
return 0;
}
static int rkx121_bridge_enable(struct serdes *serdes)
{
return 0;
}
static int rkx121_bridge_disable(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_panel_ops rkx121_panel_ops = {
.init = rkx121_bridge_init,
.enable = rkx121_bridge_enable,
.disable = rkx121_bridge_disable,
};
static int rkx121_pinctrl_config_get(struct serdes *serdes,
unsigned int pin,
unsigned long *config)
{
return 0;
}
static int rkx121_pinctrl_config_set(struct serdes *serdes,
unsigned int pin,
unsigned long *configs,
unsigned int num_configs)
{
return 0;
}
static int rkx121_pinctrl_set_mux(struct serdes *serdes, unsigned int func_selector,
unsigned int group_selector)
{
return 0;
}
static struct serdes_chip_pinctrl_ops rkx121_pinctrl_ops = {
.pin_config_get = rkx121_pinctrl_config_get,
.pin_config_set = rkx121_pinctrl_config_set,
.set_mux = rkx121_pinctrl_set_mux,
};
static int rkx121_gpio_direction_input(struct serdes *serdes, int gpio)
{
return 0;
}
static int rkx121_gpio_direction_output(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int rkx121_gpio_get_level(struct serdes *serdes, int gpio)
{
return 0;
}
static int rkx121_gpio_set_level(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int rkx121_gpio_set_config(struct serdes *serdes, int gpio, unsigned long config)
{
return 0;
}
static int rkx121_gpio_to_irq(struct serdes *serdes, int gpio)
{
return 0;
}
static struct serdes_chip_gpio_ops rkx121_gpio_ops = {
.direction_input = rkx121_gpio_direction_input,
.direction_output = rkx121_gpio_direction_output,
.get_level = rkx121_gpio_get_level,
.set_level = rkx121_gpio_set_level,
.set_config = rkx121_gpio_set_config,
.to_irq = rkx121_gpio_to_irq,
};
static int rkx121_pm_suspend(struct serdes *serdes)
{
return 0;
}
static int rkx121_pm_resume(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_pm_ops rkx121_pm_ops = {
.suspend = rkx121_pm_suspend,
.resume = rkx121_pm_resume,
};
static int rkx121_irq_lock_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static int rkx121_irq_err_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static struct serdes_chip_irq_ops rkx121_irq_ops = {
.lock_handle = rkx121_irq_lock_handle,
.err_handle = rkx121_irq_err_handle,
};
struct serdes_chip_data serdes_rkx121_data = {
.name = "rkx121",
.serdes_type = TYPE_DES,
.serdes_id = ROCKCHIP_ID_RKX121,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
.regmap_config = &rkx121_regmap_config,
.pinctrl_info = &rkx121_pinctrl_info,
.panel_ops = &rkx121_panel_ops,
.pinctrl_ops = &rkx121_pinctrl_ops,
.gpio_ops = &rkx121_gpio_ops,
.pm_ops = &rkx121_pm_ops,
.irq_ops = &rkx121_irq_ops,
};
EXPORT_SYMBOL_GPL(serdes_rkx121_data);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,25 @@
# SPDX-License-Identifier: GPL-2.0
#
# rohm serdes drivers configuration
#
menuconfig SERDES_DISPLAY_CHIP_ROHM
tristate "rohm serdes device support"
default y
help
Enable this to be able to choose the drivers for controlling the
rohm serdes.
if SERDES_DISPLAY_CHIP_ROHM
config SERDES_DISPLAY_CHIP_ROHM_BU18TL82
tristate "rohm bu18tl82 serdes"
default y
help
To support rohm bu18tl82 display serdes.
config SERDES_DISPLAY_CHIP_ROHM_BU18RL82
tristate "rohm bu18rl82 serdes"
default y
help
To support rohm bu18rl82 display serdes.
endif

View File

@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
#
# rohm display serdes drivers configuration
#
obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18TL82) += rohm-bu18tl82.o
obj-$(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18RL82) += rohm-bu18rl82.o

View File

@@ -0,0 +1,460 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* maxim-bu18rl82.c -- I2C register interface access for bu18rl82 serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "../core.h"
#include "rohm-bu18rl82.h"
#define PINCTRL_GROUP(a, b, c) { .name = a, .pins = b, .num_pins = c}
static bool bu18rl82_volatile_reg(struct device *dev, unsigned int reg)
{
return true;
}
static struct regmap_config bu18rl82_regmap_config = {
.name = "bu18rl82",
.reg_bits = 16,
.val_bits = 8,
.max_register = 0x0700,
.volatile_reg = bu18rl82_volatile_reg,
.cache_type = REGCACHE_RBTREE,
};
static int BU18RL82_GPIO0_pins[] = {0};
static int BU18RL82_GPIO1_pins[] = {1};
static int BU18RL82_GPIO2_pins[] = {2};
static int BU18RL82_GPIO3_pins[] = {3};
static int BU18RL82_GPIO4_pins[] = {4};
static int BU18RL82_GPIO5_pins[] = {5};
static int BU18RL82_GPIO6_pins[] = {6};
static int BU18RL82_GPIO7_pins[] = {7};
#define GROUP_DESC(nm) \
{ \
.name = #nm, \
.pins = nm ## _pins, \
.num_pins = ARRAY_SIZE(nm ## _pins), \
}
struct serdes_function_data {
u8 gpio_rx_en:1;
u16 gpio_id;
};
static const char *serdes_gpio_groups[] = {
"BU18RL82_GPIO0", "BU18RL82_GPIO1", "BU18RL82_GPIO2", "BU18RL82_GPIO3",
"BU18RL82_GPIO4", "BU18RL82_GPIO5", "BU18RL82_GPIO6", "BU18RL82_GPIO7",
};
/*des -> ser -> soc*/
#define FUNCTION_DESC_GPIO_INPUT(id) \
{ \
.name = "DES_TO_SER_GPIO"#id, \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
.data = (void *)(const struct serdes_function_data []) { \
{ .gpio_rx_en = 1, .gpio_id = id + 2 } \
}, \
} \
/*soc -> ser -> des*/
#define FUNCTION_DESC_GPIO_OUTPUT(id) \
{ \
.name = "SER_GPIO"#id"_TO_DES", \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
.data = (void *)(const struct serdes_function_data []) { \
{ .gpio_rx_en = 0, .gpio_id = id + 2 } \
}, \
} \
/*des -> device*/
#define FUNCTION_DESC_GPIO_OUTPUT_HIGH() \
{ \
.name = "DES_GPIO_OUTPUT_HIGH", \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
.data = (void *)(const struct serdes_function_data []) { \
{ .gpio_rx_en = 0, .gpio_id = 1 } \
}, \
} \
#define FUNCTION_DESC_GPIO_OUTPUT_LOW() \
{ \
.name = "DES_GPIO_OUTPUT_LOW", \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
.data = (void *)(const struct serdes_function_data []) { \
{ .gpio_rx_en = 0, .gpio_id = 0 } \
}, \
} \
static struct pinctrl_pin_desc bu18rl82_pins_desc[] = {
PINCTRL_PIN(ROHM_BU18RL82_GPIO0, "BU18RL82_GPIO0"),
PINCTRL_PIN(ROHM_BU18RL82_GPIO1, "BU18RL82_GPIO1"),
PINCTRL_PIN(ROHM_BU18RL82_GPIO2, "BU18RL82_GPIO2"),
PINCTRL_PIN(ROHM_BU18RL82_GPIO3, "BU18RL82_GPIO3"),
PINCTRL_PIN(ROHM_BU18RL82_GPIO4, "BU18RL82_GPIO4"),
PINCTRL_PIN(ROHM_BU18RL82_GPIO5, "BU18RL82_GPIO5"),
PINCTRL_PIN(ROHM_BU18RL82_GPIO6, "BU18RL82_GPIO6"),
PINCTRL_PIN(ROHM_BU18RL82_GPIO7, "BU18RL82_GPIO7"),
};
static struct group_desc bu18rl82_groups_desc[] = {
GROUP_DESC(BU18RL82_GPIO0),
GROUP_DESC(BU18RL82_GPIO1),
GROUP_DESC(BU18RL82_GPIO2),
GROUP_DESC(BU18RL82_GPIO3),
GROUP_DESC(BU18RL82_GPIO4),
GROUP_DESC(BU18RL82_GPIO5),
GROUP_DESC(BU18RL82_GPIO6),
GROUP_DESC(BU18RL82_GPIO7),
};
static struct function_desc bu18rl82_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_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_HIGH(),
FUNCTION_DESC_GPIO_OUTPUT_LOW(),
};
static struct serdes_chip_pinctrl_info bu18rl82_pinctrl_info = {
.pins = bu18rl82_pins_desc,
.num_pins = ARRAY_SIZE(bu18rl82_pins_desc),
.groups = bu18rl82_groups_desc,
.num_groups = ARRAY_SIZE(bu18rl82_groups_desc),
.functions = bu18rl82_functions_desc,
.num_functions = ARRAY_SIZE(bu18rl82_functions_desc),
};
static void bu18rl82_bridge_swrst(struct serdes *serdes)
{
struct device *dev = serdes->dev;
int ret;
ret = serdes_reg_write(serdes, BU18RL82_REG_RESET, BIT(0) | BIT(1) | BIT(7));
if (ret < 0)
dev_err(dev, "%s: failed to reset bu18rl82 0x11 ret=%d\n", __func__, ret);
mdelay(20);
SERDES_DBG_CHIP("%s: serdes %s ret=%d\n", __func__, serdes->chip_data->name, ret);
}
static void bu18rl82_enable_hwint(struct serdes *serdes, int enable)
{
struct device *dev = serdes->dev;
int i, ret;
for (i = 0; i < ARRAY_SIZE(bu18rl82_reg_ien); i++) {
if (enable) {
ret = serdes_reg_write(serdes, bu18rl82_reg_ien[i].reg,
bu18rl82_reg_ien[i].ien);
if (ret)
dev_err(dev, "reg 0x%04x write error\n", bu18rl82_reg_ien[i].reg);
} else {
ret = serdes_reg_write(serdes, bu18rl82_reg_ien[i].reg, 0);
if (ret)
dev_err(dev, "reg 0x%04x write error\n", bu18rl82_reg_ien[i].reg);
}
}
SERDES_DBG_CHIP("%s: serdes %s ret=%d\n", __func__,
serdes->chip_data->name, enable);
}
static int bu18rl82_bridge_init(struct serdes *serdes)
{
return 0;
bu18rl82_bridge_swrst(serdes);
return 0;
}
static int bu18rl82_bridge_enable(struct serdes *serdes)
{
int ret = 0;
/* 1:enable 0:disable */
bu18rl82_enable_hwint(serdes, 0);
SERDES_DBG_CHIP("%s: serdes %s ret=%d\n", __func__,
serdes->chip_data->name, ret);
return ret;
}
static int bu18rl82_bridge_disable(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_bridge_ops bu18rl82_bridge_ops = {
.init = bu18rl82_bridge_init,
.enable = bu18rl82_bridge_enable,
.disable = bu18rl82_bridge_disable,
};
static int bu18rl82_pinctrl_config_get(struct serdes *serdes,
unsigned int pin, unsigned long *config)
{
enum pin_config_param param = pinconf_to_config_param(*config);
unsigned int bu18rl82_gpio_sw_reg, bu18rl82_gpio_pden_reg, bu18rl82_gpio_oen_reg;
u16 arg = 0;
serdes_reg_read(serdes, bu18rl82_gpio_sw[pin].reg, &bu18rl82_gpio_sw_reg);
serdes_reg_read(serdes, bu18rl82_gpio_pden[pin].reg, &bu18rl82_gpio_pden_reg);
serdes_reg_read(serdes, bu18rl82_gpio_oen[pin].reg, &bu18rl82_gpio_oen_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_STRENGTH:
arg = FIELD_GET(BIT(2) | BIT(1), bu18rl82_gpio_sw_reg);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
arg = FIELD_GET(BIT(4), bu18rl82_gpio_pden_reg);
break;
case PIN_CONFIG_OUTPUT:
arg = FIELD_GET(BIT(3), bu18rl82_gpio_oen_reg);
break;
default:
return -EOPNOTSUPP;
}
*config = pinconf_to_config_packed(param, arg);
SERDES_DBG_CHIP("%s: serdes chip %s pin=%d arg=%d\n",
__func__, serdes->chip_data->name, pin, arg);
return 0;
}
static int bu18rl82_pinctrl_config_set(struct serdes *serdes,
unsigned int pin, unsigned long *configs,
unsigned int num_configs)
{
enum pin_config_param param;
u32 arg;
int i;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_DRIVE_STRENGTH:
serdes_set_bits(serdes, bu18rl82_gpio_sw[pin].reg,
bu18rl82_gpio_sw[pin].mask,
FIELD_PREP(BIT(2) | BIT(1), arg));
SERDES_DBG_CHIP("%s: serdes chip %s pin=%d i=%d drive-strength arg=0x%x\n",
__func__, serdes->chip_data->name, pin, i, arg);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
serdes_set_bits(serdes, bu18rl82_gpio_pden[pin].reg,
bu18rl82_gpio_pden[i].mask,
FIELD_PREP(BIT(4), arg));
SERDES_DBG_CHIP("%s: serdes chip %s pin=%d i=%d pull-down arg=0x%x\n",
__func__, serdes->chip_data->name, pin, i, arg);
break;
break;
case PIN_CONFIG_OUTPUT:
serdes_set_bits(serdes, bu18rl82_gpio_oen[pin].reg,
bu18rl82_gpio_oen[i].mask,
FIELD_PREP(BIT(3), arg));
SERDES_DBG_CHIP("%s: serdes chip %s pin=%d i=%d output arg=0x%x\n",
__func__, serdes->chip_data->name, pin, i, arg);
break;
default:
return -EOPNOTSUPP;
}
}
return 0;
}
static int bu18rl82_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, offset;
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 *fdata = func->data;
for (i = 0; i < grp->num_pins; i++) {
offset = grp->pins[i] - pinctrl->pin_base;
if (offset > 7)
dev_err(serdes->dev, "%s gpio offset=%d too large > 7\n",
serdes->chip_data->name, offset);
else
SERDES_DBG_CHIP("%s: serdes chip %s gpio_id=0x%x, offset=%d\n",
__func__, serdes->chip_data->name, fdata->gpio_id, offset);
serdes_set_bits(serdes, bu18rl82_gpio_oen[offset].reg,
bu18rl82_gpio_oen[offset].mask,
FIELD_PREP(BIT(3), fdata->gpio_rx_en));
serdes_set_bits(serdes, bu18rl82_gpio_id_low[offset].reg,
bu18rl82_gpio_id_low[offset].mask,
FIELD_PREP(GENMASK(7, 0),
(fdata->gpio_id & 0xff)));
serdes_set_bits(serdes, bu18rl82_gpio_id_high[offset].reg,
bu18rl82_gpio_id_high[offset].mask,
FIELD_PREP(GENMASK(2, 0),
((fdata->gpio_id >> 8) & 0x7)));
serdes_set_bits(serdes, bu18rl82_gpio_pden[offset].reg,
bu18rl82_gpio_pden[offset].mask,
FIELD_PREP(BIT(4), 0));
}
}
return 0;
}
static struct serdes_chip_pinctrl_ops bu18rl82_pinctrl_ops = {
.pin_config_get = bu18rl82_pinctrl_config_get,
.pin_config_set = bu18rl82_pinctrl_config_set,
.set_mux = bu18rl82_pinctrl_set_mux,
};
static int bu18rl82_gpio_direction_input(struct serdes *serdes, int gpio)
{
return 0;
}
static int bu18rl82_gpio_direction_output(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int bu18rl82_gpio_get_level(struct serdes *serdes, int gpio)
{
return 0;
}
static int bu18rl82_gpio_set_level(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int bu18rl82_gpio_set_config(struct serdes *serdes, int gpio, unsigned long config)
{
return 0;
}
static int bu18rl82_gpio_to_irq(struct serdes *serdes, int gpio)
{
return 0;
}
static struct serdes_chip_gpio_ops bu18rl82_gpio_ops = {
.direction_input = bu18rl82_gpio_direction_input,
.direction_output = bu18rl82_gpio_direction_output,
.get_level = bu18rl82_gpio_get_level,
.set_level = bu18rl82_gpio_set_level,
.set_config = bu18rl82_gpio_set_config,
.to_irq = bu18rl82_gpio_to_irq,
};
static int bu18rl82_pm_suspend(struct serdes *serdes)
{
return 0;
}
static int bu18rl82_pm_resume(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_pm_ops bu18rl82_pm_ops = {
.suspend = bu18rl82_pm_suspend,
.resume = bu18rl82_pm_resume,
};
static int bu18rl82_irq_lock_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static int bu18rl82_irq_err_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static struct serdes_chip_irq_ops bu18rl82_irq_ops = {
.lock_handle = bu18rl82_irq_lock_handle,
.err_handle = bu18rl82_irq_err_handle,
};
struct serdes_chip_data serdes_bu18rl82_data = {
.name = "bu18rl82",
.serdes_type = TYPE_DES,
.serdes_id = ROHM_ID_BU18RL82,
.bridge_type = TYPE_BRIDGE_BRIDGE,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
.regmap_config = &bu18rl82_regmap_config,
.pinctrl_info = &bu18rl82_pinctrl_info,
.bridge_ops = &bu18rl82_bridge_ops,
.pinctrl_ops = &bu18rl82_pinctrl_ops,
.gpio_ops = &bu18rl82_gpio_ops,
.pm_ops = &bu18rl82_pm_ops,
.irq_ops = &bu18rl82_irq_ops,
};
EXPORT_SYMBOL_GPL(serdes_bu18rl82_data);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,376 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* include/linux/mfd/serdes/gpio.h -- GPIO for different serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*
*/
#ifndef __MFD_SERDES_ROHM_BU18RL82_H__
#define __MFD_SERDES_ROHM_BU18RL82_H__
#define BU18RL82_REG_RESET 0X000E
#define BU18RL82_BLOCK_EN_CLLRX0 0x0011 //h [0] 1b1
#define BU18RL82_BLOCK_EN_LVDSTX0 0x0011 //h [1] 1b0
#define BU18RL82_BLOCK_EN_VPLL0 0x0011 //h [3] 1b0
#define BU18RL82_BLOCK_EN_SSCG0 0x0011 //h [4] 1b0
#define BU18RL82_BLOCK_EN_CLLRX1 0x0012 //h [0] 1b1
#define BU18RL82_BLOCK_EN_LVDSTX1 0x0012 //h [1] 1b0
#define BU18RL82_BLOCK_EN_VPLL1 0x0012 //h [3] 1b0
#define BU18RL82_BLOCK_EN_SSCG1 0x0012 //h [4] 1b0
#define BU18RL82_BLOCK_EN_CLLTX 0x0013 //h [0] 1b0
#define BU18RL82_BLOCK_EN_FSAFETY 0x0013 //h [1] 1b0
#define BU18RL82_IO_SW_GPIO0 0x0057 //h [2:1] 2b00
#define BU18RL82_IO_OEN_GPIO0 0x0057 //h [3] 1b1
#define BU18RL82_IO_PDEN_GPIO0 0x0057 //h [4] 1b1
#define BU18RL82_IO_SW_GPIO1 0x005A //h [2:1] 2b00
#define BU18RL82_IO_OEN_GPIO1 0x005A //h [3] 1b1
#define BU18RL82_IO_PDEN_GPIO1 0x005A //h [4] 1b1
#define BU18RL82_IO_SW_GPIO2 0x005D //h [2:1] 2b00
#define BU18RL82_IO_OEN_GPIO2 0x005D //h [3] 1b1
#define BU18RL82_IO_PDEN_GPIO2 0x005D //h [4] 1b1
#define BU18RL82_IO_SW_GPIO3 0x0060 //h [2:1] 2b00
#define BU18RL82_IO_OEN_GPIO3 0x0060 //h [3] 1b1
#define BU18RL82_IO_PDEN_GPIO3 0x0060 //h [4] 1b1
#define BU18RL82_IO_SW_GPIO4 0x0063 //h [2:1] 2b00
#define BU18RL82_IO_OEN_GPIO4 0x0063 //h [3] 1b1
#define BU18RL82_IO_PDEN_GPIO4 0x0063 //h [4] 1b1
#define BU18RL82_IO_SW_GPIO5 0x0066 //h [2:1] 2b00
#define BU18RL82_IO_OEN_GPIO5 0x0066 //h [2:1] 2b00
#define BU18RL82_IO_PDEN_GPIO5 0x0066 //h [3] 1b1
#define BU18RL82_IO_SW_GPIO6 0x0069 //h [2:1] 2b00
#define BU18RL82_IO_OEN_GPIO6 0x0069 //h [3] 1b1
#define BU18RL82_IO_PDEN_GPIO6 0x0069 //h [4] 1b1
#define BU18RL82_IO_SW_GPIO7 0x006C //h [2:1] 2b00
#define BU18RL82_IO_OEN_GPIO7 0x006C //h [3] 1b1
#define BU18RL82_IO_PDEN_GPIO7 0x006C //h [4] 1b1
/*
* gpio register for define connection with des gpiox.
* 11bits such as 0x002c:002b=[b2..b0 b7...b0]
*
* default value:
* ser gpio0-->des gpio0
* ser gpio1-->des gpio1
* ser gpio2-->des gpio2
* ser gpio3-->des gpio3
*/
#define BU18RL82_GPIO_SEL0_HIGH 0x0059 //h [2:0],
#define BU18RL82_GPIO_SEL0_LOW 0x0058 //h [7:0]} 11h002
#define BU18RL82_GPIO_SEL1_HIGH 0x005C //h [2:0],
#define BU18RL82_GPIO_SEL1_LOW 0x005B //h [7:0]} 11h003
#define BU18RL82_GPIO_SEL2_HIGH 0x005F //h [2:0],
#define BU18RL82_GPIO_SEL2_LOW 0x005E //h [7:0]} 11h012
#define BU18RL82_GPIO_SEL3_HIGH 0x0062 //h [2:0],
#define BU18RL82_GPIO_SEL3_LOW 0x0061 //h [7:0]} 11h013
#define BU18RL82_GPIO_SEL4_HIGH 0x0065 //h [2:0],
#define BU18RL82_GPIO_SEL4_LOW 0x0064 //h [7:0]} 11h006
#define BU18RL82_GPIO_SEL5_HIGH 0x0068 //h [2:0],
#define BU18RL82_GPIO_SEL5_LOW 0x0067 //h [7:0]} 11h007
#define BU18RL82_GPIO_SEL6_HIGH 0x006B //h [2:0],
#define BU18RL82_GPIO_SEL6_LOW 0x006A //h [7:0]} 11h008
#define BU18RL82_GPIO_SEL7_HIGH 0x006E //h [2:0],
#define BU18RL82_GPIO_SEL7_LOW 0x006D //h [7:0]} 11h009
/*gpio register for define bu18rl82 gpio pin, and gpio0 to gpio0 default*/
#define BU18RL82_BCCTX0__SEL_GPI0 0x042B //h [5:0] 6h02
#define BU18RL82_BCCTX0__SEL_GPI1 0x042C //h [5:0] 6h03
#define BU18RL82_BCCTX0__SEL_GPI2 0x042D //h [5:0] 6h04
#define BU18RL82_BCCTX0__SEL_GPI3 0x042E //h [5:0] 6h05
#define BU18RL82_BCCTX0__SEL_GPI4 0x042F //h [5:0] 6h06
#define BU18RL82_BCCTX0__SEL_GPI5 0x0430 //h [5:0] 6h07
#define BU18RL82_BCCTX0__SEL_GPI6 0x0431 //h [5:0] 6h08
#define BU18RL82_BCCTX0__SEL_GPI7 0x0432 //h [5:0] 6h09
#define BU18RL82_BCCTX1__SEL_GPI0 0x052B //h [5:0] 6h02
#define BU18RL82_BCCTX1__SEL_GPI1 0x052C //h [5:0] 6h03
#define BU18RL82_BCCTX1__SEL_GPI2 0x052D //h [5:0] 6h04
#define BU18RL82_BCCTX1__SEL_GPI3 0x052E //h [5:0] 6h05
#define BU18RL82_BCCTX1__SEL_GPI4 0x052F //h [5:0] 6h06
#define BU18RL82_BCCTX1__SEL_GPI5 0x0530 //h [5:0] 6h07
#define BU18RL82_BCCTX1__SEL_GPI6 0x0531 //h [5:0] 6h08
#define BU18RL82_BCCTX1__SEL_GPI7 0x0532 //h [5:0] 6h09
#define BU18RL82_IEN_CLLRX0_LINK_UNLOCK 0x0109 //h [1] 1b0
#define BU18RL82_IEN_CLLRX0_BIT_ERR 0x0109 //h [3] 1b0
#define BU18RL82_IEN_CLLRX0_ERR_CNT_OVF 0x0109 //h [4] 1b0
#define BU18RL82_IEN_CLLRX1_LINK_UNLOCK 0x010B //h [1] 1b0
#define BU18RL82_IEN_CLLRX1_BIT_ERR 0x010B //h [3] 1b0
#define BU18RL82_IEN_CLLRX1_ERR_CNT_OVF 0x010B //h [4] 1b0
#define BU18RL82_IEN_FCCRX0_CRCERR 0x010D //h [0] 1b0
#define BU18RL82_IEN_FCCRX1_CRCERR 0x010E //h [0] 1b0
#define BU18RL82_IEN_BCCDES0_ERR_CRC 0x010F //h [3] 1b0
#define BU18RL82_IEN_CLLRX0_CRCERR_R 0x0110 //h [0] 1b0
#define BU18RL82_IEN_CLLRX0_CRCERR_G 0x0110 //h [1] 1b0
#define BU18RL82_IEN_CLLRX0_CRCERR_B 0x0110 //h [2] 1b0
#define BU18RL82_IEN_CLLRX1_CRCERR_R 0x0111 //h [0] 1b0
#define BU18RL82_IEN_CLLRX1_CRCERR_G 0x0111 //h [1] 1b0
#define BU18RL82_IEN_CLLRX1_CRCERR_B 0x0111 //h [2] 1b0
#define BU18RL82_IEN_FS_IMG_STATUS0 0x0112 //h [0] 1b0
#define BU18RL82_IEN_FS_IMG_STATUS1 0x0112 //h [1] 1b0
#define BU18RL82_IEN_FS_IMG_STATUS2 0x0112 //h [2] 1b0
#define BU18RL82_IEN_FS_IMG_STATUS3 0x0112 //h [3] 1b0
#define BU18RL82_IEN_FS_IMG_ERR_REGION0 0x0113 //h [0] 1b0
#define BU18RL82_IEN_FS_IMG_ERR_REGION1 0x0113 //h [1] 1b0
#define BU18RL82_IEN_FS_IMG_ERR_REGION2 0x0113 //h [2] 1b0
#define BU18RL82_IEN_FS_IMG_ERR_REGION3 0x0113 //h [3] 1b0
#define BU18RL82_IEN_FS_IMG_ERR_REGION4 0x0113 //h [4] 1b0
#define BU18RL82_IEN_FS_IMG_ERR_REGION5 0x0113 //h [5] 1b0
#define BU18RL82_IEN_FS_IMG_ERR_REGION6 0x0113 //h [6] 1b0
#define BU18RL82_IEN_FS_IMG_ERR_REGION7 0x0113 //h [7] 1b0
#define BU18RL82_IEN_IO_STUCK_GPIO0 0x0114 //h [0] 1b0
#define BU18RL82_IEN_IO_STUCK_GPIO1 0x0114 //h [1] 1b0
#define BU18RL82_IEN_IO_STUCK_GPIO2 0x0114 //h [2] 1b0
#define BU18RL82_IEN_IO_STUCK_GPIO3 0x0114 //h [3] 1b0
#define BU18RL82_IEN_IO_STUCK_GPIO4 0x0114 //h [4] 1b0
#define BU18RL82_IEN_IO_STUCK_GPIO5 0x0114 //h [5] 1b0
#define BU18RL82_IEN_IO_STUCK_GPIO6 0x0114 //h [6] 1b0
#define BU18RL82_IEN_IO_STUCK_GPIO7 0x0114 //h [7] 1b0
#define BU18RL82_IEN_IO_STUCK_IRQ 0x0115 //h [1] 1b0
#define BU18RL82_IEN_IDS_UNSTABLE 0x0115 //h [7] 1b0
#define BU18RL82_IEN_I2C_A_TIMEOUT 0x0116 //h [0] 1b0
#define BU18RL82_IEN_I2C_A_XMIT_ERR 0x0116 //h [1] 1b0
#define BU18RL82_IEN_REGCRC_ERR_PAGE0 0x0117 //h [0] 1b0
#define BU18RL82_IEN_REGCRC_ERR_PAGE1 0x0117 //h [1] 1b0
#define BU18RL82_IEN_REGCRC_ERR_PAGE2 0x0117 //h [2] 1b0
#define BU18RL82_IEN_REGCRC_ERR_PAGE3 0x0117 //h [3] 1b0
#define BU18RL82_IEN_REGCRC_ERR_PAGE4 0x0117 //h [4] 1b0
#define BU18RL82_IEN_REGCRC_ERR_PAGE5 0x0117 //h [5] 1b0
#define BU18RL82_IEN_REGCRC_ERR_PAGE6 0x0117 //h [6] 1b0
#define BU18RL82_IEN_REGCRC_ERR_PAGE7 0x0117 //h [7] 1b0
#define BU18RL82_IEN_CLKDETECT_CLKIN_STOP 0x0118 //h [0] 1b0
#define BU18RL82_IEN_CLKDETECT_CLKIN_UNLOCK 0x0118 //h [1] 1b0
#define BU18RL82_IEN_CLKDETECT_OSC_STOP 0x0118 //h [4] 1b0
#define BU18RL82_IEN_CLKDETECT_OSC_UNLOCK 0x0118 //h [5] 1b0
#define BU18RL82_IEN_CLKDETECT_CLLRX0_PCLK_STOP 0x0119 //h [0] 1b0
#define BU18RL82_IEN_CLKDETECT_CLLRX0_PCLK_UNLOCK 0x0119 //h [1] 1b0
#define BU18RL82_IEN_CLKDETECT_LVDSTX0_CLK_STOP 0x0119 //h [4] 1b0
#define BU18RL82_IEN_CLKDETECT_LVDSTX0_CLK_UNLOCK 0x0119 //h [5] 1b0
#define BU18RL82_IEN_CLKDETECT_CLLRX1_PCLK_STOP 0x011A //h [0] 1b0
#define BU18RL82_IEN_CLKDETECT_CLLRX1_PCLK_UNLOCK 0x011A //h [1] 1b0
#define BU18RL82_IEN_CLKDETECT_LVDSTX1_CLK_STOP 0x011A //h [4] 1b0
#define BU18RL82_IEN_CLKDETECT_LVDSTX1_CLK_UNLOCK 0x011A //h [5] 1b0
#define BU18RL82_IEN_CLKDETECT_CLLTX0_SCLK_STOP 0x011B //h [0] 1b0
#define BU18RL82_IEN_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x011B //h [1] 1b0
#define BU18RL82_IEN_CLKDETECT_CLLTX0_PLLREF_STOP 0x011B //h [4] 1b0
#define BU18RL82_IEN_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x011B //h [5] 1b0
#define BU18RL82_IEN_CLKDETECT_LVDSTX0_PLLREF_STOP 0x011C //h [0] 1b0
#define BU18RL82_IEN_CLKDETECT_LVDSTX0_PLLREF_UNLOCK0x011C //h [1] 1b0
#define BU18RL82_IEN_CLKDETECT_LVDSTX1_PLLREF_STOP 0x011C //h [4] 1b0
#define BU18RL82_IEN_CLKDETECT_LVDSTX1_PLLREF_UNLOCK 0x011C //h [5] 1b0
#define BU18RL82_ISR_CLEAR_ALL 0x0105 //h [0] 1b0
#define BU18RL82_ISR_CLLRX0_LINK_UNLOCK 0x0129 //h [1] 1b0
#define BU18RL82_ISR_CLLRX0_BIT_ERR 0x0129 //h [3] 1b0
#define BU18RL82_ISR_CLLRX0_ERR_CNT_OVF 0x0129 //h [4] 1b0
#define BU18RL82_ISR_CLLRX1_ERR_CNT_OVF 0x012B //h [4] 1b0
#define BU18RL82_ISR_CLLRX1_LINK_UNLOCK 0x012B //h [1] 1b0
#define BU18RL82_ISR_CLLRX1_BIT_ERR 0x012B //h [3] 1b0
#define BU18RL82_ISR_FCCRX0_CRCERR 0x012D //h [0] 1b0
#define BU18RL82_ISR_FCCRX1_CRCERR 0x012E //h [0] 1b0
#define BU18RL82_ISR_BCCDES0_ERR_CRC 0x012F //h [3] 1b0
#define BU18RL82_ISR_CLLRX0_CRCERR_R 0x0130 //h [0] 1b0
#define BU18RL82_ISR_CLLRX0_CRCERR_G 0x0130 //h [1] 1b0
#define BU18RL82_ISR_CLLRX0_CRCERR_B 0x0130 //h [2] 1b0
#define BU18RL82_ISR_CLLRX1_CRCERR_R 0x0131 //h [0] 1b0
#define BU18RL82_ISR_CLLRX1_CRCERR_G 0x0131 //h [1] 1b0
#define BU18RL82_ISR_CLLRX1_CRCERR_B 0x0131 //h [2] 1b0
#define BU18RL82_ISR_FS_IMG_STATUS0 0x0132 //h [0] 1b0
#define BU18RL82_ISR_FS_IMG_STATUS1 0x0132 //h [1] 1b0
#define BU18RL82_ISR_FS_IMG_STATUS2 0x0132 //h [2] 1b0
#define BU18RL82_ISR_FS_IMG_STATUS3 0x0132 //h [3] 1b0
#define BU18RL82_ISR_FS_IMG_ERR_REGION0 0x0133 //h [0] 1b0
#define BU18RL82_ISR_FS_IMG_ERR_REGION1 0x0133 //h [1] 1b0
#define BU18RL82_ISR_FS_IMG_ERR_REGION2 0x0133 //h [2] 1b0
#define BU18RL82_ISR_FS_IMG_ERR_REGION3 0x0133 //h [3] 1b0
#define BU18RL82_ISR_FS_IMG_ERR_REGION4 0x0133 //h [4] 1b0
#define BU18RL82_ISR_FS_IMG_ERR_REGION5 0x0133 //h [5] 1b0
#define BU18RL82_ISR_FS_IMG_ERR_REGION6 0x0133 //h [6] 1b0
#define BU18RL82_ISR_FS_IMG_ERR_REGION7 0x0133 //h [7] 1b0
#define BU18RL82_ISR_IO_STUCK_GPIO0 0x0134 //h [0] 1b0
#define BU18RL82_ISR_IO_STUCK_GPIO1 0x0134 //h [1] 1b0
#define BU18RL82_ISR_IO_STUCK_GPIO2 0x0134 //h [2] 1b0
#define BU18RL82_ISR_IO_STUCK_GPIO3 0x0134 //h [3] 1b0
#define BU18RL82_ISR_IO_STUCK_GPIO4 0x0134 //h [4] 1b0
#define BU18RL82_ISR_IO_STUCK_GPIO5 0x0134 //h [5] 1b0
#define BU18RL82_ISR_IO_STUCK_GPIO6 0x0134 //h [6] 1b0
#define BU18RL82_ISR_IO_STUCK_GPIO7 0x0134 //h [7] 1b0
#define BU18RL82_ISR_IO_STUCK_IRQ 0x0135 //h [1] 1b0
#define BU18RL82_ISR_IDS_UNSTABLE 0x0135 //h [7] 1b0
#define BU18RL82_ISR_I2C_A_TIMEOUT 0x0136 //h [0] 1b0
#define BU18RL82_ISR_I2C_A_XMIT_ERR 0x0136 //h [1] 1b0
#define BU18RL82_ISR_REGCRC_ERR_PAGE0 0x0137 //h [0] 1b0
#define BU18RL82_ISR_REGCRC_ERR_PAGE1 0x0137 //h [1] 1b0
#define BU18RL82_ISR_REGCRC_ERR_PAGE2 0x0137 //h [2] 1b0
#define BU18RL82_ISR_REGCRC_ERR_PAGE3 0x0137 //h [3] 1b0
#define BU18RL82_ISR_REGCRC_ERR_PAGE4 0x0137 //h [4] 1b0
#define BU18RL82_ISR_REGCRC_ERR_PAGE5 0x0137 //h [5] 1b0
#define BU18RL82_ISR_REGCRC_ERR_PAGE6 0x0137 //h [6] 1b0
#define BU18RL82_ISR_REGCRC_ERR_PAGE7 0x0137 //h [7] 1b0
#define BU18RL82_ISR_CLKDETECT_CLKIN_STOP 0x0138 //h [0] 1b0
#define BU18RL82_ISR_CLKDETECT_CLKIN_UNLOCK 0x0138 //h [1] 1b0
#define BU18RL82_ISR_CLKDETECT_OSC_STOP 0x0138 //h [4] 1b0
#define BU18RL82_ISR_CLKDETECT_OSC_UNLOCK 0x0138 //h [5] 1b0
#define BU18RL82_ISR_CLKDETECT_CLLRX0_PCLK_STOP 0x0139 //h [0] 1b0
#define BU18RL82_ISR_CLKDETECT_CLLRX0_PCLK_UNLOCK 0x0139 //h [1] 1b0
#define BU18RL82_ISR_CLKDETECT_LVDSTX0_CLK_STOP 0x0139 //h [4] 1b0
#define BU18RL82_ISR_CLKDETECT_LVDSTX0_CLK_UNLOCK 0x0139 //h [5] 1b0
#define BU18RL82_ISR_CLKDETECT_CLLRX1_PCLK_STOP 0x013A //h [0] 1b0
#define BU18RL82_ISR_CLKDETECT_CLLRX1_PCLK_UNLOCK 0x013A //h [1] 1b0
#define BU18RL82_ISR_CLKDETECT_LVDSTX1_CLK_STOP 0x013A //h [4] 1b0
#define BU18RL82_ISR_CLKDETECT_LVDSTX1_CLK_UNLOCK 0x013A //h [5] 1b0
#define BU18RL82_ISR_CLKDETECT_CLLTX0_SCLK_STOP 0x013B //h [0] 1b0
#define BU18RL82_ISR_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x013B //h [1] 1b0
#define BU18RL82_ISR_CLKDETECT_CLLTX0_PLLREF_STOP 0x013B //h [4] 1b0
#define BU18RL82_ISR_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x013B //h [5] 1b0
#define BU18RL82_ISR_CLKDETECT_LVDSTX0_PLLREF_STOP 0x013C //h [0] 1b0
#define BU18RL82_ISR_CLKDETECT_LVDSTX0_PLLREF_UNLOCK0x013C //h [1] 1b0
#define BU18RL82_ISR_CLKDETECT_LVDSTX1_PLLREF_STOP 0x013C //h [4] 1b0
#define BU18RL82_ISR_CLKDETECT_LVDSTX1_PLLREF_UNLOCK 0x013C //h [5] 1b0
struct bu18rl82_gpio_sw_reg {
unsigned int reg;
unsigned int mask; //2/4/6/8ma
};
struct bu18rl82_gpio_oen_reg {
unsigned int reg;
unsigned int mask; //0:output 1:input
};
struct bu18rl82_gpio_pden_reg {
unsigned int reg;
unsigned int mask; //0:no pulldown 1:connect pulldown
};
struct bu18rl82_gpio_id_low_reg {
unsigned int reg;
unsigned int mask; //b2b1b0
};
struct bu18rl82_gpio_id_high_reg {
unsigned int reg;
unsigned int mask; //b11b10b9b8b7b6b5b4b3
};
static const struct bu18rl82_gpio_sw_reg bu18rl82_gpio_sw[8] = {
{BU18RL82_IO_SW_GPIO0, BIT(2) | BIT(1)},
{BU18RL82_IO_SW_GPIO1, BIT(2) | BIT(1)},
{BU18RL82_IO_SW_GPIO2, BIT(2) | BIT(1)},
{BU18RL82_IO_SW_GPIO3, BIT(2) | BIT(1)},
{BU18RL82_IO_SW_GPIO4, BIT(2) | BIT(1)},
{BU18RL82_IO_SW_GPIO5, BIT(2) | BIT(1)},
{BU18RL82_IO_SW_GPIO6, BIT(2) | BIT(1)},
{BU18RL82_IO_SW_GPIO7, BIT(2) | BIT(1)},
};
static const struct bu18rl82_gpio_oen_reg bu18rl82_gpio_oen[8] = {
{BU18RL82_IO_OEN_GPIO0, BIT(3)},
{BU18RL82_IO_OEN_GPIO1, BIT(3)},
{BU18RL82_IO_OEN_GPIO2, BIT(3)},
{BU18RL82_IO_OEN_GPIO3, BIT(3)},
{BU18RL82_IO_OEN_GPIO4, BIT(3)},
{BU18RL82_IO_OEN_GPIO5, BIT(3)},
{BU18RL82_IO_OEN_GPIO6, BIT(3)},
{BU18RL82_IO_OEN_GPIO7, BIT(3)},
};
static const struct bu18rl82_gpio_pden_reg bu18rl82_gpio_pden[8] = {
{BU18RL82_IO_PDEN_GPIO0, BIT(4)},
{BU18RL82_IO_PDEN_GPIO1, BIT(4)},
{BU18RL82_IO_PDEN_GPIO2, BIT(4)},
{BU18RL82_IO_PDEN_GPIO3, BIT(4)},
{BU18RL82_IO_PDEN_GPIO4, BIT(4)},
{BU18RL82_IO_PDEN_GPIO5, BIT(4)},
{BU18RL82_IO_PDEN_GPIO6, BIT(4)},
{BU18RL82_IO_PDEN_GPIO7, BIT(4)},
};
static const struct bu18rl82_gpio_id_low_reg bu18rl82_gpio_id_low[8] = {
{BU18RL82_GPIO_SEL0_LOW, GENMASK(7, 0)},
{BU18RL82_GPIO_SEL1_LOW, GENMASK(7, 0)},
{BU18RL82_GPIO_SEL2_LOW, GENMASK(7, 0)},
{BU18RL82_GPIO_SEL3_LOW, GENMASK(7, 0)},
{BU18RL82_GPIO_SEL4_LOW, GENMASK(7, 0)},
{BU18RL82_GPIO_SEL5_LOW, GENMASK(7, 0)},
{BU18RL82_GPIO_SEL6_LOW, GENMASK(7, 0)},
{BU18RL82_GPIO_SEL7_LOW, GENMASK(7, 0)},
};
static const struct bu18rl82_gpio_id_high_reg bu18rl82_gpio_id_high[8] = {
{BU18RL82_GPIO_SEL0_HIGH, GENMASK(2, 0)},
{BU18RL82_GPIO_SEL1_HIGH, GENMASK(2, 0)},
{BU18RL82_GPIO_SEL2_HIGH, GENMASK(2, 0)},
{BU18RL82_GPIO_SEL3_HIGH, GENMASK(2, 0)},
{BU18RL82_GPIO_SEL4_HIGH, GENMASK(2, 0)},
{BU18RL82_GPIO_SEL5_HIGH, GENMASK(2, 0)},
{BU18RL82_GPIO_SEL6_HIGH, GENMASK(2, 0)},
{BU18RL82_GPIO_SEL7_HIGH, GENMASK(2, 0)},
};
struct bu18rl82_ien_reg {
unsigned int reg;
unsigned int ien;
};
struct bu18rl82_isr_reg {
unsigned int reg;
unsigned int isr;
};
struct bu18rl82_gpio_reg {
unsigned int reg;
unsigned int val;
};
static const struct bu18rl82_ien_reg bu18rl82_reg_ien[18] = {
{BU18RL82_IEN_CLLRX0_LINK_UNLOCK, BIT(1) | BIT(3) | BIT(4)},
{BU18RL82_IEN_CLLRX1_LINK_UNLOCK, BIT(1) | BIT(3) | BIT(4)},
{BU18RL82_IEN_FCCRX0_CRCERR, BIT(0)},
{BU18RL82_IEN_FCCRX1_CRCERR, BIT(0)},
{BU18RL82_IEN_BCCDES0_ERR_CRC, BIT(3)},
{BU18RL82_IEN_CLLRX0_CRCERR_R, BIT(0) | BIT(1) | BIT(2)},
{BU18RL82_IEN_CLLRX1_CRCERR_R, BIT(0) | BIT(1) | BIT(2)},
{BU18RL82_IEN_FS_IMG_STATUS0, BIT(0) | BIT(1) | BIT(2) | BIT(3)},
{BU18RL82_IEN_FS_IMG_ERR_REGION0, 0xff},
{BU18RL82_IEN_IO_STUCK_GPIO0, 0xff},
{BU18RL82_IEN_IO_STUCK_IRQ, BIT(1) | BIT(7)},
{BU18RL82_IEN_I2C_A_TIMEOUT, BIT(0) | BIT(1)},
{BU18RL82_IEN_REGCRC_ERR_PAGE0, 0xff},
{BU18RL82_IEN_CLKDETECT_CLKIN_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18RL82_IEN_CLKDETECT_CLLRX0_PCLK_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18RL82_IEN_CLKDETECT_CLLRX1_PCLK_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18RL82_IEN_CLKDETECT_CLLTX0_SCLK_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18RL82_IEN_CLKDETECT_LVDSTX0_PLLREF_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
};
static const struct bu18rl82_isr_reg bu18rl82_reg_isr[18] = {
{BU18RL82_ISR_CLLRX0_LINK_UNLOCK, BIT(1) | BIT(3) | BIT(4)},
{BU18RL82_ISR_CLLRX1_LINK_UNLOCK, BIT(1) | BIT(3) | BIT(4)},
{BU18RL82_ISR_FCCRX0_CRCERR, BIT(0)},
{BU18RL82_ISR_FCCRX1_CRCERR, BIT(0)},
{BU18RL82_ISR_BCCDES0_ERR_CRC, BIT(3)},
{BU18RL82_ISR_CLLRX0_CRCERR_R, BIT(0) | BIT(1) | BIT(2)},
{BU18RL82_ISR_CLLRX1_CRCERR_R, BIT(0) | BIT(1) | BIT(2)},
{BU18RL82_ISR_FS_IMG_STATUS0, BIT(0) | BIT(1) | BIT(2) | BIT(3)},
{BU18RL82_ISR_FS_IMG_ERR_REGION0, 0xff},
{BU18RL82_ISR_IO_STUCK_GPIO0, 0xff},
{BU18RL82_ISR_IO_STUCK_IRQ, BIT(1) | BIT(7)},
{BU18RL82_ISR_I2C_A_TIMEOUT, BIT(0) | BIT(1)},
{BU18RL82_ISR_REGCRC_ERR_PAGE0, 0xff},
{BU18RL82_ISR_CLKDETECT_CLKIN_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18RL82_ISR_CLKDETECT_CLLRX0_PCLK_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18RL82_ISR_CLKDETECT_CLLRX1_PCLK_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18RL82_ISR_CLKDETECT_CLLTX0_SCLK_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18RL82_ISR_CLKDETECT_LVDSTX0_PLLREF_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
};
#endif

View File

@@ -0,0 +1,461 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* maxim-bu18rl82.c -- I2C register interface access for bu18rl82 serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "../core.h"
#include "rohm-bu18tl82.h"
#define PINCTRL_GROUP(a, b, c) { .name = a, .pins = b, .num_pins = c}
static bool bu18tl82_volatile_reg(struct device *dev, unsigned int reg)
{
return true;
}
static struct regmap_config bu18tl82_regmap_config = {
.name = "bu18tl82",
.reg_bits = 16,
.val_bits = 8,
.max_register = 0x0700,
.volatile_reg = bu18tl82_volatile_reg,
.cache_type = REGCACHE_RBTREE,
};
static int BU18TL82_GPIO0_pins[] = {0};
static int BU18TL82_GPIO1_pins[] = {1};
static int BU18TL82_GPIO2_pins[] = {2};
static int BU18TL82_GPIO3_pins[] = {3};
static int BU18TL82_GPIO4_pins[] = {4};
static int BU18TL82_GPIO5_pins[] = {5};
static int BU18TL82_GPIO6_pins[] = {6};
static int BU18TL82_GPIO7_pins[] = {7};
#define GROUP_DESC(nm) \
{ \
.name = #nm, \
.pins = nm ## _pins, \
.num_pins = ARRAY_SIZE(nm ## _pins), \
}
struct serdes_function_data {
u8 gpio_rx_en:1;
u16 gpio_id;
};
static const char *serdes_gpio_groups[] = {
"BU18TL82_GPIO0", "BU18TL82_GPIO1", "BU18TL82_GPIO2", "BU18TL82_GPIO3",
"BU18TL82_GPIO4", "BU18TL82_GPIO5", "BU18TL82_GPIO6", "BU18TL82_GPIO7",
};
/*des -> ser -> soc*/
#define FUNCTION_DESC_GPIO_INPUT(id) \
{ \
.name = "DES_GPIO"#id"_TO_SER", \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
.data = (void *)(const struct serdes_function_data []) { \
{ .gpio_rx_en = 0, .gpio_id = (id < 8) ? (id + 2) : (id + 3) } \
}, \
} \
/*soc -> ser -> des*/
#define FUNCTION_DESC_GPIO_OUTPUT(id) \
{ \
.name = "SER_TO_DES_GPIO"#id, \
.group_names = serdes_gpio_groups, \
.num_group_names = ARRAY_SIZE(serdes_gpio_groups), \
.data = (void *)(const struct serdes_function_data []) { \
{ .gpio_rx_en = 1, .gpio_id = (id < 8) ? (id + 2) : (id + 3) } \
}, \
} \
static struct pinctrl_pin_desc bu18tl82_pins_desc[] = {
PINCTRL_PIN(ROHM_BU18TL82_GPIO0, "BU18TL82_GPIO0"),
PINCTRL_PIN(ROHM_BU18TL82_GPIO1, "BU18TL82_GPIO1"),
PINCTRL_PIN(ROHM_BU18TL82_GPIO2, "BU18TL82_GPIO2"),
PINCTRL_PIN(ROHM_BU18TL82_GPIO3, "BU18TL82_GPIO3"),
PINCTRL_PIN(ROHM_BU18TL82_GPIO4, "BU18TL82_GPIO4"),
PINCTRL_PIN(ROHM_BU18TL82_GPIO5, "BU18TL82_GPIO5"),
PINCTRL_PIN(ROHM_BU18TL82_GPIO6, "BU18TL82_GPIO6"),
PINCTRL_PIN(ROHM_BU18TL82_GPIO7, "BU18TL82_GPIO7"),
};
static struct group_desc bu18tl82_groups_desc[] = {
GROUP_DESC(BU18TL82_GPIO0),
GROUP_DESC(BU18TL82_GPIO1),
GROUP_DESC(BU18TL82_GPIO2),
GROUP_DESC(BU18TL82_GPIO3),
GROUP_DESC(BU18TL82_GPIO4),
GROUP_DESC(BU18TL82_GPIO5),
GROUP_DESC(BU18TL82_GPIO6),
GROUP_DESC(BU18TL82_GPIO7),
};
static struct function_desc bu18tl82_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_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),
};
static struct serdes_chip_pinctrl_info bu18tl82_pinctrl_info = {
.pins = bu18tl82_pins_desc,
.num_pins = ARRAY_SIZE(bu18tl82_pins_desc),
.groups = bu18tl82_groups_desc,
.num_groups = ARRAY_SIZE(bu18tl82_groups_desc),
.functions = bu18tl82_functions_desc,
.num_functions = ARRAY_SIZE(bu18tl82_functions_desc),
};
static void bu18tl82_bridge_swrst(struct serdes *serdes)
{
struct device *dev = serdes->dev;
int ret;
return;
ret = serdes_reg_write(serdes, BU18TL82_REG_SWRST_INTERNAL, 0x00ef);
if (ret < 0)
dev_err(dev, "%s: failed to reset serdes 0x11 ret=%d\n", __func__, ret);
ret = serdes_reg_write(serdes, BU18TL82_REG_SWRST_MIPIRX, 0x0003);
if (ret < 0)
dev_err(dev, "%s: failed to reset serdes 0x12 ret=%d\n", __func__, ret);
msleep(20);
SERDES_DBG_CHIP("%s: %s ret=%d\n", __func__, serdes->chip_data->name, ret);
}
static void bu18tl82_enable_hwint(struct serdes *serdes, int enable)
{
struct device *dev = serdes->dev;
int i, ret;
for (i = 0; i < ARRAY_SIZE(bu18tl82_reg_ien); i++) {
if (enable) {
ret = serdes_reg_write(serdes, bu18tl82_reg_ien[i].reg,
bu18tl82_reg_ien[i].ien);
if (ret)
dev_err(dev, "reg 0x%04x write error\n", bu18tl82_reg_ien[i].reg);
} else {
ret = serdes_reg_write(serdes, bu18tl82_reg_ien[i].reg, 0);
if (ret)
dev_err(dev, "reg 0x%04x write error\n", bu18tl82_reg_ien[i].reg);
}
}
SERDES_DBG_CHIP("%s: %s enable=%d\n", __func__, serdes->chip_data->name, enable);
}
static int bu18tl82_bridge_init(struct serdes *serdes)
{
if (serdes->enable_gpio) {
gpiod_direction_output(serdes->enable_gpio, 1);
msleep(20);
}
if (serdes->reset_gpio) {
gpiod_direction_output(serdes->reset_gpio, 0);
msleep(30);
} else {
bu18tl82_bridge_swrst(serdes);
}
return 0;
}
static int bu18tl82_bridge_enable(struct serdes *serdes)
{
return 0;
}
static int bu18tl82_bridge_disable(struct serdes *serdes)
{
return 0;
}
static int bu18tl82_bridge_get_modes(struct serdes *serdes)
{
return 0;
}
static int bu18tl82_bridge_pre_enable(struct serdes *serdes)
{
int ret = 0;
/* 1:enable 0:disable */
bu18tl82_enable_hwint(serdes, 0);
msleep(160);
SERDES_DBG_CHIP("%s: %s ret=%d\n", __func__, serdes->chip_data->name, ret);
return ret;
}
static struct serdes_chip_bridge_ops bu18tl82_bridge_ops = {
.init = bu18tl82_bridge_init,
.get_modes = bu18tl82_bridge_get_modes,
.pre_enable = bu18tl82_bridge_pre_enable,
.enable = bu18tl82_bridge_enable,
.disable = bu18tl82_bridge_disable,
};
static int bu18tl82_pinctrl_config_get(struct serdes *serdes,
unsigned int pin, unsigned long *config)
{
enum pin_config_param param = pinconf_to_config_param(*config);
unsigned int bu18tl82_gpio_sw_reg, bu18tl82_gpio_pden_reg, bu18tl82_gpio_oen_reg;
u16 arg = 0;
serdes_reg_read(serdes, bu18tl82_gpio_sw[pin].reg, &bu18tl82_gpio_sw_reg);
serdes_reg_read(serdes, bu18tl82_gpio_pden[pin].reg, &bu18tl82_gpio_pden_reg);
serdes_reg_read(serdes, bu18tl82_gpio_oen[pin].reg, &bu18tl82_gpio_oen_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_STRENGTH:
arg = FIELD_GET(BIT(2) | BIT(1), bu18tl82_gpio_sw_reg);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
arg = FIELD_GET(BIT(4), bu18tl82_gpio_pden_reg);
break;
case PIN_CONFIG_OUTPUT:
arg = FIELD_GET(BIT(3), bu18tl82_gpio_oen_reg);
break;
default:
return -EOPNOTSUPP;
}
*config = pinconf_to_config_packed(param, arg);
SERDES_DBG_CHIP("%s: serdes chip %s pin=%d arg=%d\n", __func__,
serdes->chip_data->name, pin, arg);
return 0;
}
static int bu18tl82_pinctrl_config_set(struct serdes *serdes,
unsigned int pin, unsigned long *configs,
unsigned int num_configs)
{
enum pin_config_param param;
u32 arg;
int i;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_DRIVE_STRENGTH:
serdes_set_bits(serdes, bu18tl82_gpio_sw[pin].reg,
bu18tl82_gpio_sw[pin].mask,
FIELD_PREP(BIT(2) | BIT(1), arg));
SERDES_DBG_CHIP("%s: serdes chip %s pin=%d i=%d drive-strength arg=0x%x\n",
__func__, serdes->chip_data->name, pin, i, arg);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
serdes_set_bits(serdes, bu18tl82_gpio_pden[pin].reg,
bu18tl82_gpio_pden[i].mask,
FIELD_PREP(BIT(4), arg));
SERDES_DBG_CHIP("%s: serdes chip %s pin=%d i=%d pull-down arg=0x%x\n",
__func__, serdes->chip_data->name, pin, i, arg);
break;
break;
case PIN_CONFIG_OUTPUT:
serdes_set_bits(serdes, bu18tl82_gpio_oen[pin].reg,
bu18tl82_gpio_oen[i].mask,
FIELD_PREP(BIT(3), arg));
SERDES_DBG_CHIP("%s: serdes chip %s pin=%d i=%d output arg=0x%x\n",
__func__, serdes->chip_data->name, pin, i, arg);
break;
default:
return -EOPNOTSUPP;
}
}
return 0;
}
static int bu18tl82_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, offset;
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 *fdata = func->data;
for (i = 0; i < grp->num_pins; i++) {
offset = grp->pins[i] - pinctrl->pin_base;
if (offset > 7)
dev_err(serdes->dev, "%s gpio offset=%d too large > 7\n",
serdes->chip_data->name, offset);
else
SERDES_DBG_CHIP("%s: serdes chip %s gpio_id=0x%x, offset=%d\n",
__func__, serdes->chip_data->name,
fdata->gpio_id, offset);
serdes_set_bits(serdes, bu18tl82_gpio_oen[offset].reg,
bu18tl82_gpio_oen[offset].mask,
FIELD_PREP(BIT(3), fdata->gpio_rx_en));
serdes_set_bits(serdes, bu18tl82_gpio_id_low[offset].reg,
bu18tl82_gpio_id_low[offset].mask,
FIELD_PREP(GENMASK(7, 0), (fdata->gpio_id & 0xff)));
serdes_set_bits(serdes, bu18tl82_gpio_id_high[offset].reg,
bu18tl82_gpio_id_high[offset].mask,
FIELD_PREP(GENMASK(2, 0), ((fdata->gpio_id >> 8) & 0x7)));
serdes_set_bits(serdes, bu18tl82_gpio_pden[offset].reg,
bu18tl82_gpio_pden[offset].mask,
FIELD_PREP(BIT(4), 0));
}
}
return 0;
}
static struct serdes_chip_pinctrl_ops bu18tl82_pinctrl_ops = {
.pin_config_get = bu18tl82_pinctrl_config_get,
.pin_config_set = bu18tl82_pinctrl_config_set,
.set_mux = bu18tl82_pinctrl_set_mux,
};
static int bu18tl82_gpio_direction_input(struct serdes *serdes, int gpio)
{
return 0;
}
static int bu18tl82_gpio_direction_output(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int bu18tl82_gpio_get_level(struct serdes *serdes, int gpio)
{
return 0;
}
static int bu18tl82_gpio_set_level(struct serdes *serdes, int gpio, int value)
{
return 0;
}
static int bu18tl82_gpio_set_config(struct serdes *serdes, int gpio, unsigned long config)
{
return 0;
}
static int bu18tl82_gpio_to_irq(struct serdes *serdes, int gpio)
{
return 0;
}
static struct serdes_chip_gpio_ops bu18tl82_gpio_ops = {
.direction_input = bu18tl82_gpio_direction_input,
.direction_output = bu18tl82_gpio_direction_output,
.get_level = bu18tl82_gpio_get_level,
.set_level = bu18tl82_gpio_set_level,
.set_config = bu18tl82_gpio_set_config,
.to_irq = bu18tl82_gpio_to_irq,
};
static int bu18tl82_pm_suspend(struct serdes *serdes)
{
return 0;
}
static int bu18tl82_pm_resume(struct serdes *serdes)
{
return 0;
}
static struct serdes_chip_pm_ops bu18tl82_pm_ops = {
.suspend = bu18tl82_pm_suspend,
.resume = bu18tl82_pm_resume,
};
static int bu18tl82_irq_lock_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static int bu18tl82_irq_err_handle(struct serdes *serdes)
{
return IRQ_HANDLED;
}
static struct serdes_chip_irq_ops bu18tl82_irq_ops = {
.lock_handle = bu18tl82_irq_lock_handle,
.err_handle = bu18tl82_irq_err_handle,
};
struct serdes_chip_data serdes_bu18tl82_data = {
.name = "bu18tl82",
.serdes_type = TYPE_SER,
.serdes_id = ROHM_ID_BU18TL82,
.sequence_init = 1,
.bridge_type = TYPE_BRIDGE_BRIDGE,
.connector_type = DRM_MODE_CONNECTOR_eDP,
.regmap_config = &bu18tl82_regmap_config,
.pinctrl_info = &bu18tl82_pinctrl_info,
.bridge_ops = &bu18tl82_bridge_ops,
.pinctrl_ops = &bu18tl82_pinctrl_ops,
.gpio_ops = &bu18tl82_gpio_ops,
.pm_ops = &bu18tl82_pm_ops,
.irq_ops = &bu18tl82_irq_ops,
};
EXPORT_SYMBOL_GPL(serdes_bu18tl82_data);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,438 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* include/linux/mfd/serdes/gpio.h -- GPIO for different serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*
*/
#ifndef __MFD_SERDES_ROHM_BU18TL82_H__
#define __MFD_SERDES_ROHM_BU18TL82_H__
#define BU18TL82_REG_SWRST_INTERNAL 0x0011
#define BU18TL82_REG_SWRST_MIPIRX 0x0012
#define BU18TL82_REG_SWRST_INTERNAL 0x0011
#define BU18TL82_REG_SWRST_MIPIRX 0x0012
#define BU18TL82_BLOCK_EN_MIPIRX0 0x0013 //h [0] 1b0
#define BU18TL82_BLOCK_EN_LVDSRX0 0x0013 //h [1] 1b0
#define BU18TL82_BLOCK_EN_CLLTX0 0x0013 //h [3] 1b0
#define BU18TL82_BLOCK_EN_VPLL0 0x0013 //h [4] 1b0
#define BU18TL82_BLOCK_EN_SSCG0 0x0013 //h [5] 1b0
#define BU18TL82_BLOCK_EN_MIPIRX1 0x0014 //h [0] 1b0
#define BU18TL82_BLOCK_EN_LVDSRX1 0x0014 //h [1] 1b0
#define BU18TL82_BLOCK_EN_CLLTX1 0x0014 //h [3] 1b0
#define BU18TL82_BLOCK_EN_VPLL1 0x0014 //h [4] 1b0
#define BU18TL82_BLOCK_EN_SSCG1 0x0014 //h [5] 1b0
/*gpio register for driver/direction/pull-down*/
#define BU18TL82_IO_SW_GPIO0 0x002A //h [2:1] 2b00
#define BU18TL82_IO_OEN_GPIO0 0x002A //h [3] 1b1
#define BU18TL82_IO_PDEN_GPIO0 0x002A //h [4] 1b1
#define BU18TL82_IO_SW_GPIO1 0x002D //h [2:1] 2b00
#define BU18TL82_IO_OEN_GPIO1 0x002D //h [3] 1b1
#define BU18TL82_IO_PDEN_GPIO1 0x002D //h [4] 1b1
#define BU18TL82_IO_SW_GPIO2 0x0030 //h [2:1] 2b00
#define BU18TL82_IO_OEN_GPIO2 0x0030 //h [3] 1b1
#define BU18TL82_IO_PDEN_GPIO2 0x0030 //h [4] 1b1
#define BU18TL82_IO_SW_GPIO3 0x0033 //h [2:1] 2b00
#define BU18TL82_IO_OEN_GPIO3 0x0033 //h [3] 1b1
#define BU18TL82_IO_PDEN_GPIO3 0x0033 //h [4] 1b1
#define BU18TL82_IO_SW_GPIO4 0x0036 //h [2:1] 2b00
#define BU18TL82_IO_OEN_GPIO4 0x0036 //h [3] 1b1
#define BU18TL82_IO_PDEN_GPIO4 0x0036 //h [4] 1b1
#define BU18TL82_IO_SW_GPIO5 0x0039 //h [2:1] 2b00
#define BU18TL82_IO_OEN_GPIO5 0x0039 //h [3] 1b1
#define BU18TL82_IO_PDEN_GPIO5 0x0039 //h [4] 1b1
#define BU18TL82_IO_SW_GPIO6 0x003C //h [2:1] 2b00
#define BU18TL82_IO_OEN_GPIO6 0x003C //h [3] 1b1
#define BU18TL82_IO_PDEN_GPIO6 0x003C //h [4] 1b1
#define BU18TL82_IO_SW_GPIO7 0x003F //h [2:1] 2b00
#define BU18TL82_IO_OEN_GPIO7 0x003F //h [3] 1b1
#define BU18TL82_IO_PDEN_GPIO7 0x003F //h [4] 1b1
/*
* gpio register for define connection with des gpiox.
* 11bits such as 0x002c:002b=[b2..b0 b7...b0]
*
* default value:
* ser gpio0-->des gpio0
* ser gpio1-->des gpio1
* ser gpio2-->des gpio2
* ser gpio3-->des gpio3
*/
#define BU18TL82_GPIO_SEL0_HIGH 0x002C //h [2:0],
#define BU18TL82_GPIO_SEL0_LOW 0x002B //h [7:0] 11h002
#define BU18TL82_GPIO_SEL1_HIGH 0x002F //h [2:0],
#define BU18TL82_GPIO_SEL1_LOW 0x002E //h [7:0] 11h003
#define BU18TL82_GPIO_SEL2_HIGH 0x0032 //h [2:0],
#define BU18TL82_GPIO_SEL2_LOW 0x0031 //h [7:0] 11h004
#define BU18TL82_GPIO_SEL3_HIGH 0x0035 //h [2:0],
#define BU18TL82_GPIO_SEL3_LOW 0x0034 //h [7:0] 11h005
#define BU18TL82_GPIO_SEL4_HIGH 0x0038 //h [2:0],
#define BU18TL82_GPIO_SEL4_LOW 0x0037 //h [7:0] 11h006
#define BU18TL82_GPIO_SEL5_HIGH 0x003B //h [2:0],
#define BU18TL82_GPIO_SEL5_LOW 0x003A //h [7:0] 11h007
/*datasheet about gpio6/7 need modify*/
#define BU18TL82_GPIO_SEL6_LOW 0x003E //h [2:0],
#define BU18TL82_GPIO_SEL6_HIGH 0x003D //h [7:0] 11h008
#define BU18TL82_GPIO_SEL7_LOW 0x0041 //h [2:0],
#define BU18TL82_GPIO_SEL7_HIGH 0x0040 //h [7:0] 11h009
/*gpio register for define bu18tl82 gpio pin, and gpio0 to gpio0 default*/
#define BU18TL82_FCCTX0_SEL_GPI0 0x02A7 //h [4:0] 5h02
#define BU18TL82_FCCTX0_SEL_GPI1 0x02A8 //h [4:0] 5h03
#define BU18TL82_FCCTX0_SEL_GPI2 0x02A9 //h [4:0] 5h04
#define BU18TL82_FCCTX0_SEL_GPI3 0x02AA //h [4:0] 5h05
#define BU18TL82_FCCTX0_SEL_GPI4 0x02AB //h [4:0] 5h06
#define BU18TL82_FCCTX0_SEL_GPI5 0x02AC //h [4:0] 5h07
#define BU18TL82_FCCTX0_SEL_GPI6 0x02AD //h [4:0] 5h08
#define BU18TL82_FCCTX0_SEL_GPI7 0x02AE //h [4:0] 5h09
#define BU18TL82_CLLTX0_SEL_GPI0 0x02AF //h [4:0] 5h04
#define BU18TL82_CLLTX0_SEL_GPI1 0x02B0 //h [4:0] 5h05
#define BU18TL82_FCCTX1_SEL_GPI0 0x03A7 //h [4:0] 5h02
#define BU18TL82_FCCTX1_SEL_GPI1 0x03A8 //h [4:0] 5h03
#define BU18TL82_FCCTX1_SEL_GPI2 0x03A9 //h [4:0] 5h04
#define BU18TL82_FCCTX1_SEL_GPI3 0x03AA //h [4:0] 5h05
#define BU18TL82_FCCTX1_SEL_GPI4 0x03AB //h [4:0] 5h06
#define BU18TL82_FCCTX1_SEL_GPI5 0x03AC //h [4:0] 5h07
#define BU18TL82_FCCTX1_SEL_GPI6 0x03AD //h [4:0] 5h08
#define BU18TL82_FCCTX1_SEL_GPI7 0x03AE //h [4:0] 5h09
#define BU18TL82_CLLTX1_SEL_GPI0 0x03AF //h [4:0] 5h04
#define BU18TL82_CLLTX1_SEL_GPI1 0x03B0 //h [4:0] 5h05
/*write 1'b0 to this register to clear all isr register value8*/
#define BU18TL82_ISR_CLEAR_ALL 0x0105 //h[0]
#define BU18TL82_ISR_BCCDES0_ERR_CRC 0x0131 //h [3] 1b0
#define BU18TL82_ISR_BCCRX0_STATUS_NEAR_LOST 0x0131 //h[7]
#define BU18TL82_ISR_BCCDES1_ERR_CRC 0x0132 //h [3] 1b0
#define BU18TL82_ISR_BCCRX1_STATUS_NEAR_LOST 0x0132 //h[7]
#define BU18TL82_ISR_MIPIRX0_SOT_ERR 0x0133 //h[0]
#define BU18TL82_ISR_MIPIRX0_SOT_SYNC_ERR 0x0133 //h[1]
#define BU18TL82_ISR_MIPIRX0_EOT_SYNC_ERR 0x0133 //h[2]
#define BU18TL82_ISR_MIPIRX0_ECC1BIT_ERR 0x0134 //h[0]
#define BU18TL82_ISR_MIPIRX0_ECCMULT_ERR 0x0134 //h[1]
#define BU18TL82_ISR_MIPIRX0_CRC_ERR 0x0134 //h[2]
#define BU18TL82_ISR_MIPIRX1_SOT_ERR 0x0135 //h[0]
#define BU18TL82_ISR_MIPIRX1_SOT_SYNC_ERR 0x0135 //h[1]
#define BU18TL82_ISR_MIPIRX1_EOT_SYNC_ERR 0x0135 //h[2]
#define BU18TL82_ISR_MIPIRX1_ECC1BIT_ERR 0x0136 //h[0]
#define BU18TL82_ISR_MIPIRX1_ECCMULT_ERR 0x0136 //h[1]
#define BU18TL82_ISR_MIPIRX1_CRC_ERR 0x0136 //h[2]
#define BU18TL82_ISR_LVDSRX0_V_TOTAL_MAX_ERR 0x0137 //h[0]
#define BU18TL82_ISR_LVDSRX0_V_TOTAL_MIN_ERR 0x0137 //h[1]
#define BU18TL82_ISR_LVDSRX0_V_ACTIVE_MAX_ERR 0x0137 //h[2]
#define BU18TL82_ISR_LVDSRX0_V_ACTIVE_MIN_ERR 0x0137 //h[3]
#define BU18TL82_ISR_LVDSRX0_H_TOTAL_MAX_ERR 0x0137 //h[4]
#define BU18TL82_ISR_LVDSRX0_H_TOTAL_MIN_ERR 0x0137 //h[5]
#define BU18TL82_ISR_LVDSRX0_H_ACTIVE_MAX_ERR 0x0137 //h[6]
#define BU18TL82_ISR_LVDSRX0_H_ACTIVE_MIN_ERR 0x0137 //h[7]
#define BU18TL82_ISR_LVDSRX1_V_TOTAL_MAX_ERR 0x0138 //h[0]
#define BU18TL82_ISR_LVDSRX1_V_TOTAL_MIN_ERR 0x0138 //h[1]
#define BU18TL82_ISR_LVDSRX1_V_ACTIVE_MAX_ERR 0x0138 //h[2]
#define BU18TL82_ISR_LVDSRX1_V_ACTIVE_MIN_ERR 0x0138 //h[3]
#define BU18TL82_ISR_LVDSRX1_H_TOTAL_MAX_ERR 0x0138 //h[4]
#define BU18TL82_ISR_LVDSRX1_H_TOTAL_MIN_ERR 0x0138 //h[5]
#define BU18TL82_ISR_LVDSRX1_H_ACTIVE_MAX_ERR 0x0138 //h[6]
#define BU18TL82_ISR_LVDSRX1_H_ACTIVE_MIN_ERR 0x0138 //h[7]
#define BU18TL82_ISR_IO_STUCK_GPIO0 0x0139 //h[0]
#define BU18TL82_ISR_IO_STUCK_GPIO1 0x0139 //h[1]
#define BU18TL82_ISR_IO_STUCK_GPIO2 0x0139 //h[2]
#define BU18TL82_ISR_IO_STUCK_GPIO3 0x0139 //h[3]
#define BU18TL82_ISR_IO_STUCK_GPIO4 0x0139 //h[4]
#define BU18TL82_ISR_IO_STUCK_GPIO5 0x0139 //h[5]
#define BU18TL82_ISR_IO_STUCK_GPIO6 0x0139 //h[6]
#define BU18TL82_ISR_IO_STUCK_GPIO7 0x0139 //h[7]
#define BU18TL82_ISR_IO_STUCK_IRQ 0x013a //h[1]
#define BU18TL82_ISR_IDS_UNSTABLE 0x013a //h [7] 1b0
#define BU18TL82_ISR_I2C_A_TIMEOUT 0x013b //h [0] 1b0
#define BU18TL82_ISR_I2C_A_XMIT_ERR 0x013b //h [1] 1b0
#define BU18TL82_ISR_I2C_B_TIMEOUT 0x013c //h [0] 1b0
#define BU18TL82_ISR_I2C_B_XMIT_ERR 0x013c //h [1] 1b0
#define BU18TL82_ISR_REGCRC_ERR_PAGE0 0x013d //h[0]
#define BU18TL82_ISR_REGCRC_ERR_PAGE1 0x013d //h[1]
#define BU18TL82_ISR_REGCRC_ERR_PAGE2 0x013d //h[2]
#define BU18TL82_ISR_REGCRC_ERR_PAGE3 0x013d //h[3]
#define BU18TL82_ISR_REGCRC_ERR_PAGE4 0x013d //h[4]
#define BU18TL82_ISR_REGCRC_ERR_PAGE5 0x013d //h[5]
#define BU18TL82_ISR_CLKDETECT_CLKIN0_STOP 0x013e //h [0] 1b0
#define BU18TL82_ISR_CLKDETECT_CLKIN0_UNLOCK 0x013e //h [1] 1b0
#define BU18TL82_ISR_CLKDETECT_OSC_STOP 0x013e //h [4] 1b0
#define BU18TL82_ISR_CLKDETECT_OSC_UNLOCK 0x013e //h [5] 1b0
#define BU18TL82_ISR_CLKDETECT_CLKIN1_STOP 0x013f //h [0] 1b0
#define BU18TL82_ISR_CLKDETECT_CLKIN1_UNLOCK 0x013f //h [1] 1b0
#define BU18TL82_ISR_CLKDETECT_LVDSRX0_STOP 0x0140 //h [0] 1b0
#define BU18TL82_ISR_CLKDETECT_LVDSRX0_UNLOCK 0x0140 //h [1] 1b0
#define BU18TL82_ISR_CLKDETECT_MIPIRX0_STOP 0x0140 //h [4] 1b0
#define BU18TL82_ISR_CLKDETECT_MIPIRX0_UNLOCK 0x0140 //h [5] 1b0
#define BU18TL82_ISR_CLKDETECT_LVDSRX1_STOP 0x0141 //h [0] 1b0
#define BU18TL82_ISR_CLKDETECT_LVDSRX1_UNLOCK 0x0141 //h [1] 1b0
#define BU18TL82_ISR_CLKDETECT_MIPIRX1_STOP 0x0141 //h [4] 1b0
#define BU18TL82_ISR_CLKDETECT_MIPIRX1_UNLOCK 0x0141 //h [5] 1b0
#define BU18TL82_ISR_CLKDETECT_CLLTX0_SCLK_STOP 0x0142 //h [0] 1b0
#define BU18TL82_ISR_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x0142 //h [1] 1b0
#define BU18TL82_ISR_CLKDETECT_CLLTX0_PLLREF_STOP 0x0142 //h [4] 1b0
#define BU18TL82_ISR_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x0142 //h [5] 1b0
#define BU18TL82_ISR_CLKDETECT_CLLTX1_SCLK_STOP 0x0143 //h [0] 1b0
#define BU18TL82_ISR_CLKDETECT_CLLTX1_SCLK_UNLOCK 0x0143 //h [1] 1b0
#define BU18TL82_ISR_CLKDETECT_CLLTX1_PLLREF_STOP 0x0143 //h [4] 1b0
#define BU18TL82_ISR_CLKDETECT_CLLTX1_PLLREF_UNLOCK 0x0143 //h [5] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR00 0x0149 //h [0] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR01 0x0149 //h [1] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR02 0x0149 //h [2] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR03 0x0149 //h [3] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR04 0x0149 //h [4] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR05 0x0149 //h [5] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR06 0x0149 //h [6] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR07 0x0149 //h [7] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR08 0x014a //h [0] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR09 0x014a //h [1] 1b0
#define BU18TL82_ISR_STATUS_RX0_ISR10 0x014a //h [2] 1b0
#define BU18TL82_IEN_BCCDES0_ERR_CRC 0x0109 //h [3] 1b0
#define BU18TL82_IEN_BCCRX0_STATUS_NEAR_LOST 0x0109 //h[7]
#define BU18TL82_IEN_BCCDES1_ERR_CRC 0x010A //h [3] 1b0
#define BU18TL82_IEN_BCCRX1_STATUS_NEAR_LOST 0x010A //h[7]
#define BU18TL82_IEN_MIPIRX0_SOT_ERR 0x010B //h[0]
#define BU18TL82_IEN_MIPIRX0_SOT_SYNC_ERR 0x010B //h[1]
#define BU18TL82_IEN_MIPIRX0_EOT_SYNC_ERR 0x010B //h[2]
#define BU18TL82_IEN_MIPIRX0_ECC1BIT_ERR 0x010C //h[0]
#define BU18TL82_IEN_MIPIRX0_ECCMULT_ERR 0x010C //h[1]
#define BU18TL82_IEN_MIPIRX0_CRC_ERR 0x010C //h[2]
#define BU18TL82_IEN_MIPIRX1_SOT_ERR 0x010D //h[0]
#define BU18TL82_IEN_MIPIRX1_SOT_SYNC_ERR 0x010D //h[1]
#define BU18TL82_IEN_MIPIRX1_EOT_SYNC_ERR 0x010D //h[2]
#define BU18TL82_IEN_MIPIRX1_ECC1BIT_ERR 0x010E //h[0]
#define BU18TL82_IEN_MIPIRX1_ECCMULT_ERR 0x010E //h[1]
#define BU18TL82_IEN_MIPIRX1_CRC_ERR 0x010E //h[2]
#define BU18TL82_IEN_LVDSRX0_V_TOTAL_MAX_ERR 0x010F //h[0]
#define BU18TL82_IEN_LVDSRX0_V_TOTAL_MIN_ERR 0x010F //h[1]
#define BU18TL82_IEN_LVDSRX0_V_ACTIVE_MAX_ERR 0x010F //h[2]
#define BU18TL82_IEN_LVDSRX0_V_ACTIVE_MIN_ERR 0x010F //h[3]
#define BU18TL82_IEN_LVDSRX0_H_TOTAL_MAX_ERR 0x010F //h[4]
#define BU18TL82_IEN_LVDSRX0_H_TOTAL_MIN_ERR 0x010F //h[5]
#define BU18TL82_IEN_LVDSRX0_H_ACTIVE_MAX_ERR 0x010F //h[6]
#define BU18TL82_IEN_LVDSRX0_H_ACTIVE_MIN_ERR 0x010F //h[7]
#define BU18TL82_IEN_LVDSRX1_V_TOTAL_MAX_ERR 0x0110 //h[0]
#define BU18TL82_IEN_LVDSRX1_V_TOTAL_MIN_ERR 0x0110 //h[1]
#define BU18TL82_IEN_LVDSRX1_V_ACTIVE_MAX_ERR 0x0110 //h[2]
#define BU18TL82_IEN_LVDSRX1_V_ACTIVE_MIN_ERR 0x0110 //h[3]
#define BU18TL82_IEN_LVDSRX1_H_TOTAL_MAX_ERR 0x0110 //h[4]
#define BU18TL82_IEN_LVDSRX1_H_TOTAL_MIN_ERR 0x0110 //h[5]
#define BU18TL82_IEN_LVDSRX1_H_ACTIVE_MAX_ERR 0x0110 //h[6]
#define BU18TL82_IEN_LVDSRX1_H_ACTIVE_MIN_ERR 0x0110 //h[7]
#define BU18TL82_IEN_IO_STUCK_GPIO0 0x0111 //h[0]
#define BU18TL82_IEN_IO_STUCK_GPIO1 0x0111 //h[1]
#define BU18TL82_IEN_IO_STUCK_GPIO2 0x0111 //h[2]
#define BU18TL82_IEN_IO_STUCK_GPIO3 0x0111 //h[3]
#define BU18TL82_IEN_IO_STUCK_GPIO4 0x0111 //h[4]
#define BU18TL82_IEN_IO_STUCK_GPIO5 0x0111 //h[5]
#define BU18TL82_IEN_IO_STUCK_GPIO6 0x0111 //h[6]
#define BU18TL82_IEN_IO_STUCK_GPIO7 0x0111 //h[7]
#define BU18TL82_IEN_IO_STUCK_IRQ 0x0112 //h[1]
#define BU18TL82_IEN_IDS_UNSTABLE 0x0112 //h [7] 1b0
#define BU18TL82_IEN_I2C_A_TIMEOUT 0x0113 //h [0] 1b0
#define BU18TL82_IEN_I2C_A_XMIT_ERR 0x0113 //h [1] 1b0
#define BU18TL82_IEN_I2C_B_TIMEOUT 0x0114 //h [0] 1b0
#define BU18TL82_IEN_I2C_B_XMIT_ERR 0x0114 //h [1] 1b0
#define BU18TL82_IEN_REGCRC_ERR_PAGE0 0x0115 //h[0]
#define BU18TL82_IEN_REGCRC_ERR_PAGE1 0x0115 //h[1]
#define BU18TL82_IEN_REGCRC_ERR_PAGE2 0x0115 //h[2]
#define BU18TL82_IEN_REGCRC_ERR_PAGE3 0x0115 //h[3]
#define BU18TL82_IEN_REGCRC_ERR_PAGE4 0x0115 //h[4]
#define BU18TL82_IEN_REGCRC_ERR_PAGE5 0x0115 //h[5]
#define BU18TL82_IEN_CLKDETECT_CLKIN0_STOP 0x0116 //h [0] 1b0
#define BU18TL82_IEN_CLKDETECT_CLKIN0_UNLOCK 0x0116 //h [1] 1b0
#define BU18TL82_IEN_CLKDETECT_OSC_STOP 0x0116 //h [4] 1b0
#define BU18TL82_IEN_CLKDETECT_OSC_UNLOCK 0x0116 //h [5] 1b0
#define BU18TL82_IEN_CLKDETECT_CLKIN1_STOP 0x0117 //h [0] 1b0
#define BU18TL82_IEN_CLKDETECT_CLKIN1_UNLOCK 0x0117 //h [1] 1b0
#define BU18TL82_IEN_CLKDETECT_LVDSRX0_STOP 0x0118 //h [0] 1b0
#define BU18TL82_IEN_CLKDETECT_LVDSRX0_UNLOCK 0x0118 //h [1] 1b0
#define BU18TL82_IEN_CLKDETECT_MIPIRX0_STOP 0x0118 //h [4] 1b0
#define BU18TL82_IEN_CLKDETECT_MIPIRX0_UNLOCK 0x0118 //h [5] 1b0
#define BU18TL82_IEN_CLKDETECT_LVDSRX1_STOP 0x0119 //h [0] 1b0
#define BU18TL82_IEN_CLKDETECT_LVDSRX1_UNLOCK 0x0119 //h [1] 1b0
#define BU18TL82_IEN_CLKDETECT_MIPIRX1_STOP 0x0119 //h [4] 1b0
#define BU18TL82_IEN_CLKDETECT_MIPIRX1_UNLOCK 0x0119 //h [5] 1b0
#define BU18TL82_IEN_CLKDETECT_CLLTX0_SCLK_STOP 0x011A //h [0] 1b0
#define BU18TL82_IEN_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x011A //h [1] 1b0
#define BU18TL82_IEN_CLKDETECT_CLLTX0_PLLREF_STOP 0x011A //h [4] 1b0
#define BU18TL82_IEN_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x011A //h [5] 1b0
#define BU18TL82_IEN_CLKDETECT_CLLTX1_SCLK_STOP 0x011B //h [0] 1b0
#define BU18TL82_IEN_CLKDETECT_CLLTX1_SCLK_UNLOCK 0x011B //h [1] 1b0
#define BU18TL82_IEN_CLKDETECT_CLLTX1_PLLREF_STOP 0x011B //h [4] 1b0
#define BU18TL82_IEN_CLKDETECT_CLLTX1_PLLREF_UNLOCK 0x011B //h [5] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR00 0x0121 //h [0] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR01 0x0121 //h [1] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR02 0x0121 //h [2] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR03 0x0121 //h [3] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR04 0x0121 //h [4] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR05 0x0121 //h [5] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR06 0x0121 //h [6] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR07 0x0121 //h [7] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR08 0x0122 //h [0] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR09 0x0122 //h [1] 1b0
#define BU18TL82_IEN_STATUS_RX0_ISR10 0x0122 //h [2] 1b0
struct bu18tl82_gpio_sw_reg {
unsigned int reg;
unsigned int mask; //2/4/6/8ma
};
struct bu18tl82_gpio_oen_reg {
unsigned int reg;
unsigned int mask; //0:output 1:input
};
struct bu18tl82_gpio_pden_reg {
unsigned int reg;
unsigned int mask; //0:no pulldown 1:connect pulldown
};
struct bu18tl82_gpio_id_low_reg {
unsigned int reg;
unsigned int mask; //b2b1b0
};
struct bu18tl82_gpio_id_high_reg {
unsigned int reg;
unsigned int mask; //b11b10b9b8b7b6b5b4b3
};
static const struct bu18tl82_gpio_sw_reg bu18tl82_gpio_sw[8] = {
{BU18TL82_IO_SW_GPIO0, BIT(2) | BIT(1)},
{BU18TL82_IO_SW_GPIO1, BIT(2) | BIT(1)},
{BU18TL82_IO_SW_GPIO2, BIT(2) | BIT(1)},
{BU18TL82_IO_SW_GPIO3, BIT(2) | BIT(1)},
{BU18TL82_IO_SW_GPIO4, BIT(2) | BIT(1)},
{BU18TL82_IO_SW_GPIO5, BIT(2) | BIT(1)},
{BU18TL82_IO_SW_GPIO6, BIT(2) | BIT(1)},
{BU18TL82_IO_SW_GPIO7, BIT(2) | BIT(1)},
};
static const struct bu18tl82_gpio_oen_reg bu18tl82_gpio_oen[8] = {
{BU18TL82_IO_OEN_GPIO0, BIT(3)},
{BU18TL82_IO_OEN_GPIO1, BIT(3)},
{BU18TL82_IO_OEN_GPIO2, BIT(3)},
{BU18TL82_IO_OEN_GPIO3, BIT(3)},
{BU18TL82_IO_OEN_GPIO4, BIT(3)},
{BU18TL82_IO_OEN_GPIO5, BIT(3)},
{BU18TL82_IO_OEN_GPIO6, BIT(3)},
{BU18TL82_IO_OEN_GPIO7, BIT(3)},
};
static const struct bu18tl82_gpio_pden_reg bu18tl82_gpio_pden[8] = {
{BU18TL82_IO_PDEN_GPIO0, BIT(4)},
{BU18TL82_IO_PDEN_GPIO1, BIT(4)},
{BU18TL82_IO_PDEN_GPIO2, BIT(4)},
{BU18TL82_IO_PDEN_GPIO3, BIT(4)},
{BU18TL82_IO_PDEN_GPIO4, BIT(4)},
{BU18TL82_IO_PDEN_GPIO5, BIT(4)},
{BU18TL82_IO_PDEN_GPIO6, BIT(4)},
{BU18TL82_IO_PDEN_GPIO7, BIT(4)},
};
static const struct bu18tl82_gpio_id_low_reg bu18tl82_gpio_id_low[8] = {
{BU18TL82_GPIO_SEL0_LOW, GENMASK(7, 0)},
{BU18TL82_GPIO_SEL1_LOW, GENMASK(7, 0)},
{BU18TL82_GPIO_SEL2_LOW, GENMASK(7, 0)},
{BU18TL82_GPIO_SEL3_LOW, GENMASK(7, 0)},
{BU18TL82_GPIO_SEL4_LOW, GENMASK(7, 0)},
{BU18TL82_GPIO_SEL5_LOW, GENMASK(7, 0)},
{BU18TL82_GPIO_SEL6_LOW, GENMASK(7, 0)},
{BU18TL82_GPIO_SEL7_LOW, GENMASK(7, 0)},
};
static const struct bu18tl82_gpio_id_high_reg bu18tl82_gpio_id_high[8] = {
{BU18TL82_GPIO_SEL0_HIGH, GENMASK(2, 0)},
{BU18TL82_GPIO_SEL1_HIGH, GENMASK(2, 0)},
{BU18TL82_GPIO_SEL2_HIGH, GENMASK(2, 0)},
{BU18TL82_GPIO_SEL3_HIGH, GENMASK(2, 0)},
{BU18TL82_GPIO_SEL4_HIGH, GENMASK(2, 0)},
{BU18TL82_GPIO_SEL5_HIGH, GENMASK(2, 0)},
{BU18TL82_GPIO_SEL6_HIGH, GENMASK(2, 0)},
{BU18TL82_GPIO_SEL7_HIGH, GENMASK(2, 0)},
};
struct bu18tl82_ien_reg {
unsigned int reg;
unsigned int ien;
};
struct bu18tl82_isr_reg {
unsigned int reg;
unsigned int isr;
};
static const struct bu18tl82_ien_reg bu18tl82_reg_ien[21] = {
{BU18TL82_IEN_BCCRX0_STATUS_NEAR_LOST, BIT(3) | BIT(7)},
{BU18TL82_IEN_BCCRX1_STATUS_NEAR_LOST, BIT(3) | BIT(7)},
{BU18TL82_IEN_MIPIRX0_SOT_ERR, BIT(0) | BIT(0) | BIT(2)},
{BU18TL82_IEN_MIPIRX0_ECC1BIT_ERR, BIT(0) | BIT(0) | BIT(2)},
{BU18TL82_IEN_MIPIRX1_SOT_ERR, BIT(0) | BIT(0) | BIT(2)},
{BU18TL82_IEN_MIPIRX1_ECC1BIT_ERR, BIT(0) | BIT(0) | BIT(2)},
{BU18TL82_IEN_LVDSRX0_V_TOTAL_MAX_ERR, 0XFF},
{BU18TL82_IEN_LVDSRX1_V_TOTAL_MAX_ERR, 0XFF},
{BU18TL82_IEN_IO_STUCK_GPIO0, 0XFF},
{BU18TL82_IEN_IO_STUCK_IRQ, BIT(1) | BIT(7)},
{BU18TL82_IEN_I2C_A_TIMEOUT, BIT(0) | BIT(1)},
{BU18TL82_IEN_I2C_B_TIMEOUT, BIT(0) | BIT(1)},
{BU18TL82_IEN_REGCRC_ERR_PAGE0, 0x3F},
{BU18TL82_IEN_CLKDETECT_CLKIN0_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18TL82_IEN_CLKDETECT_CLKIN1_STOP, BIT(0) | BIT(1)},
{BU18TL82_IEN_CLKDETECT_LVDSRX0_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18TL82_IEN_CLKDETECT_LVDSRX1_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18TL82_IEN_CLKDETECT_CLLTX0_SCLK_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18TL82_IEN_CLKDETECT_CLLTX1_SCLK_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18TL82_IEN_STATUS_RX0_ISR00, 0xff},
{BU18TL82_IEN_STATUS_RX0_ISR08, BIT(0) | BIT(1) | BIT(2)},
};
static const struct bu18tl82_isr_reg bu18tl82_reg_isr[21] = {
{BU18TL82_ISR_BCCRX0_STATUS_NEAR_LOST, BIT(3) | BIT(7)},
{BU18TL82_ISR_BCCRX1_STATUS_NEAR_LOST, BIT(3) | BIT(7)},
{BU18TL82_ISR_MIPIRX0_SOT_ERR, BIT(0) | BIT(0) | BIT(2)},
{BU18TL82_ISR_MIPIRX0_ECC1BIT_ERR, BIT(0) | BIT(0) | BIT(2)},
{BU18TL82_ISR_MIPIRX1_SOT_ERR, BIT(0) | BIT(0) | BIT(2)},
{BU18TL82_ISR_MIPIRX1_ECC1BIT_ERR, BIT(0) | BIT(0) | BIT(2)},
{BU18TL82_ISR_LVDSRX0_V_TOTAL_MAX_ERR, 0XFF},
{BU18TL82_ISR_LVDSRX1_V_TOTAL_MAX_ERR, 0XFF},
{BU18TL82_ISR_IO_STUCK_GPIO0, 0XFF},
{BU18TL82_ISR_IO_STUCK_IRQ, BIT(1) | BIT(7)},
{BU18TL82_ISR_I2C_A_TIMEOUT, BIT(0) | BIT(1)},
{BU18TL82_ISR_I2C_B_TIMEOUT, BIT(0) | BIT(1)},
{BU18TL82_ISR_REGCRC_ERR_PAGE0, 0x3F},
{BU18TL82_ISR_CLKDETECT_CLKIN0_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18TL82_ISR_CLKDETECT_CLKIN1_STOP, BIT(0) | BIT(1)},
{BU18TL82_ISR_CLKDETECT_LVDSRX0_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18TL82_ISR_CLKDETECT_LVDSRX1_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18TL82_ISR_CLKDETECT_CLLTX0_SCLK_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18TL82_ISR_CLKDETECT_CLLTX1_SCLK_STOP, BIT(0) | BIT(1) | BIT(4) | BIT(5)},
{BU18TL82_ISR_STATUS_RX0_ISR00, 0xff},
{BU18TL82_ISR_STATUS_RX0_ISR08, BIT(0) | BIT(1) | BIT(2)},
};
#endif

View File

@@ -0,0 +1,354 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* serdes-bridge.c -- drm bridge access for different serdes chips
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "core.h"
static struct serdes_bridge *to_serdes_bridge(struct drm_bridge *bridge)
{
return container_of(bridge, struct serdes_bridge, base_bridge);
}
static struct mipi_dsi_device *serdes_attach_dsi(struct serdes_bridge *serdes_bridge,
struct device_node *dsi_node)
{
struct mipi_dsi_device_info info = { "serdes", 0, NULL };
struct serdes *serdes = serdes_bridge->parent;
struct mipi_dsi_device *dsi;
struct mipi_dsi_host *host;
int ret;
if (serdes->chip_data->name)
memcpy(&info.type, serdes->chip_data->name, ARRAY_SIZE(info.type));
SERDES_DBG_MFD("%s: type=%s, name=%s\n", __func__,
info.type, serdes->chip_data->name);
host = of_find_mipi_dsi_host_by_node(dsi_node);
if (!host) {
dev_err(serdes_bridge->dev, "failed to find serdes dsi host\n");
return ERR_PTR(-EPROBE_DEFER);
}
dsi = mipi_dsi_device_register_full(host, &info);
if (IS_ERR(dsi)) {
dev_err(serdes_bridge->dev, "failed to create serdes dsi device\n");
return dsi;
}
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
if (serdes->chip_data->name) {
if ((!strcmp(serdes->chip_data->name, "bu18tl82")) ||
(!strcmp(serdes->chip_data->name, "bu18rl82"))) {
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET;
SERDES_DBG_MFD("%s: dsi mode MIPI_DSI_MODE_VIDEO_BURST 0x%lx\n",
__func__, dsi->mode_flags);
}
} else {
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
SERDES_DBG_MFD("%s: dsi mode MIPI_DSI_MODE_VIDEO_SYNC_PULSE 0x%lx\n",
__func__, dsi->mode_flags);
}
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err(serdes_bridge->dev, "failed to attach serdes dsi to host\n");
mipi_dsi_device_unregister(dsi);
return ERR_PTR(ret);
}
return dsi;
}
static int serdes_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct serdes_bridge *serdes_bridge = to_serdes_bridge(bridge);
struct serdes *serdes = serdes_bridge->parent;
int ret = 0;
ret = drm_of_find_panel_or_bridge(bridge->of_node, 1, -1,
&serdes_bridge->panel, &serdes_bridge->next_bridge);
if (ret) {
dev_err(serdes_bridge->dev->parent, "failed to find serdes bridge, ret=%d\n", ret);
return ret;
}
if (serdes_bridge->sel_mipi) {
dev_info(serdes_bridge->dev->parent, "serdes sel_mipi %d\n",
serdes_bridge->sel_mipi);
/* Attach primary DSI */
serdes_bridge->dsi = serdes_attach_dsi(serdes_bridge, serdes_bridge->dsi_node);
if (IS_ERR(serdes_bridge->dsi))
return PTR_ERR(serdes_bridge->dsi);
}
if (serdes_bridge->next_bridge) {
ret = drm_bridge_attach(bridge->encoder, serdes_bridge->next_bridge,
bridge, flags);
if (ret) {
if (serdes_bridge->sel_mipi)
mipi_dsi_device_unregister(serdes_bridge->dsi);
dev_err(serdes_bridge->dev->parent,
"failed to attach bridge, ret=%d\n", ret);
return ret;
}
}
if (serdes->chip_data->bridge_ops->attach)
ret = serdes->chip_data->bridge_ops->attach(serdes);
SERDES_DBG_MFD("%s: ret=%d\n", __func__, ret);
return ret;
}
static void serdes_bridge_detach(struct drm_bridge *bridge)
{
struct serdes_bridge *serdes_bridge = to_serdes_bridge(bridge);
if (serdes_bridge->sel_mipi) {
mipi_dsi_detach(serdes_bridge->dsi);
mipi_dsi_device_unregister(serdes_bridge->dsi);
}
SERDES_DBG_MFD("%s\n", __func__);
}
static void serdes_bridge_disable(struct drm_bridge *bridge)
{
struct serdes_bridge *serdes_bridge = to_serdes_bridge(bridge);
struct serdes *serdes = serdes_bridge->parent;
int ret = 0;
if (serdes_bridge->panel)
drm_panel_disable(serdes_bridge->panel);
if (serdes->chip_data->bridge_ops->disable)
ret = serdes->chip_data->bridge_ops->disable(serdes);
extcon_set_state_sync(serdes->extcon, EXTCON_JACK_VIDEO_OUT, false);
SERDES_DBG_MFD("%s: ret=%d\n", __func__, ret);
}
static void serdes_bridge_post_disable(struct drm_bridge *bridge)
{
struct serdes_bridge *serdes_bridge = to_serdes_bridge(bridge);
struct serdes *serdes = serdes_bridge->parent;
int ret = 0;
serdes_set_pinctrl_sleep(serdes);
if (serdes_bridge->panel)
ret = drm_panel_unprepare(serdes_bridge->panel);
if (serdes->chip_data->bridge_ops->post_disable)
ret = serdes->chip_data->bridge_ops->post_disable(serdes);
SERDES_DBG_MFD("%s: ret=%d\n", __func__, ret);
}
static void serdes_bridge_pre_enable(struct drm_bridge *bridge)
{
struct serdes_bridge *serdes_bridge = to_serdes_bridge(bridge);
struct serdes *serdes = serdes_bridge->parent;
int ret = 0;
if (serdes->chip_data->bridge_ops->init)
ret = serdes->chip_data->bridge_ops->init(serdes);
if (serdes->chip_data->serdes_type == TYPE_DES)
serdes_i2c_set_sequence(serdes);
if (serdes_bridge->panel)
ret = drm_panel_prepare(serdes_bridge->panel);
if (serdes->chip_data->bridge_ops->pre_enable)
ret = serdes->chip_data->bridge_ops->pre_enable(serdes);
serdes_set_pinctrl_default(serdes);
SERDES_DBG_MFD("%s: %s ret=%d\n", __func__, dev_name(serdes->dev), ret);
}
static void serdes_bridge_enable(struct drm_bridge *bridge)
{
struct serdes_bridge *serdes_bridge = to_serdes_bridge(bridge);
struct serdes *serdes = serdes_bridge->parent;
int ret = 0;
if (serdes_bridge->panel)
ret = drm_panel_enable(serdes_bridge->panel);
if (serdes->chip_data->bridge_ops->enable)
ret = serdes->chip_data->bridge_ops->enable(serdes);
if (!ret) {
extcon_set_state_sync(serdes->extcon, EXTCON_JACK_VIDEO_OUT, true);
SERDES_DBG_MFD("%s: extcon is true\n", __func__);
}
SERDES_DBG_MFD("%s: %s ret=%d\n", __func__, dev_name(serdes->dev), ret);
}
static enum drm_connector_status
serdes_bridge_detect(struct drm_bridge *bridge)
{
struct serdes_bridge *serdes_bridge = to_serdes_bridge(bridge);
struct serdes *serdes = serdes_bridge->parent;
enum drm_connector_status status = connector_status_connected;
if (serdes->chip_data->bridge_ops->detect)
status = serdes->chip_data->bridge_ops->detect(serdes);
return status;
}
static int serdes_bridge_get_modes(struct drm_bridge *bridge,
struct drm_connector *connector)
{
struct serdes_bridge *serdes_bridge = to_serdes_bridge(bridge);
struct serdes *serdes = serdes_bridge->parent;
int ret = 0;
if (serdes->chip_data->bridge_ops->get_modes)
ret = serdes->chip_data->bridge_ops->get_modes(serdes);
if (serdes_bridge->next_bridge)
ret = drm_bridge_get_modes(serdes_bridge->next_bridge, connector);
if (serdes_bridge->panel)
ret = drm_panel_get_modes(serdes_bridge->panel, connector);
SERDES_DBG_MFD("%s:name=%s, type=%d\n", __func__,
serdes->chip_data->name, serdes->type);
return ret;
}
static const struct drm_bridge_funcs serdes_bridge_funcs = {
.attach = serdes_bridge_attach,
.detach = serdes_bridge_detach,
.disable = serdes_bridge_disable,
.post_disable = serdes_bridge_post_disable,
.pre_enable = serdes_bridge_pre_enable,
.enable = serdes_bridge_enable,
.detect = serdes_bridge_detect,
.get_modes = serdes_bridge_get_modes,
.atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
};
static int serdes_bridge_probe(struct platform_device *pdev)
{
struct serdes *serdes = dev_get_drvdata(pdev->dev.parent);
struct device *dev = &pdev->dev;
struct serdes_bridge *serdes_bridge;
if (!serdes->dev)
return -1;
serdes_bridge = devm_kzalloc(dev, sizeof(*serdes_bridge), GFP_KERNEL);
if (!serdes_bridge)
return -ENOMEM;
serdes->serdes_bridge = serdes_bridge;
serdes_bridge->dev = dev;
serdes_bridge->parent = dev_get_drvdata(dev->parent);
platform_set_drvdata(pdev, serdes_bridge);
serdes_bridge->regmap = dev_get_regmap(dev->parent, NULL);
if (!serdes_bridge->regmap)
return dev_err_probe(dev, -ENODEV, "failed to get serdes regmap\n");
serdes_bridge->sel_mipi = of_property_read_bool(dev->parent->of_node, "sel-mipi");
if (serdes_bridge->sel_mipi) {
serdes_bridge->dsi_node = of_graph_get_remote_node(dev->parent->of_node, 0, -1);
if (!serdes_bridge->dsi_node)
return dev_err_probe(dev->parent, -ENODEV,
"failed to get remote node for serdes dsi\n");
SERDES_DBG_MFD("%s: sel_mipi=%d\n", __func__, serdes_bridge->sel_mipi);
}
serdes_bridge->base_bridge.funcs = &serdes_bridge_funcs;
serdes_bridge->base_bridge.of_node = dev->parent->of_node;
serdes_bridge->base_bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_MODES;
if (serdes_bridge->sel_mipi) {
serdes_bridge->base_bridge.type = DRM_MODE_CONNECTOR_DSI;
SERDES_DBG_MFD("%s: type DRM_MODE_CONNECTOR_DSI\n", __func__);
} else if (serdes_bridge->parent->chip_data->connector_type) {
serdes_bridge->base_bridge.type = serdes_bridge->parent->chip_data->connector_type;
SERDES_DBG_MFD("%s: type 0x%x\n", __func__, serdes_bridge->base_bridge.type);
} else {
serdes_bridge->base_bridge.type = DRM_MODE_CONNECTOR_eDP;
SERDES_DBG_MFD("%s: type DRM_MODE_CONNECTOR_LVDS\n", __func__);
}
drm_bridge_add(&serdes_bridge->base_bridge);
dev_info(dev, "serdes %s, serdes_bridge_probe successful mipi=%d, of_node=%s\n",
serdes->chip_data->name, serdes_bridge->sel_mipi,
serdes_bridge->base_bridge.of_node->name);
return 0;
}
static int serdes_bridge_remove(struct platform_device *pdev)
{
struct serdes_bridge *serdes_bridge = platform_get_drvdata(pdev);
drm_bridge_remove(&serdes_bridge->base_bridge);
return 0;
}
static const struct of_device_id serdes_bridge_of_match[] = {
{ .compatible = "rohm,bu18tl82-bridge", },
{ .compatible = "rohm,bu18rl82-bridge", },
{ .compatible = "maxim,max96745-bridge", },
{ .compatible = "maxim,max96752-bridge", },
{ .compatible = "maxim,max96755-bridge", },
{ .compatible = "maxim,max96772-bridge", },
{ .compatible = "rockchip,rkx111-bridge", },
{ .compatible = "rockchip,rkx121-bridge", },
{ }
};
static struct platform_driver serdes_bridge_driver = {
.driver = {
.name = "serdes-bridge",
.of_match_table = of_match_ptr(serdes_bridge_of_match),
},
.probe = serdes_bridge_probe,
.remove = serdes_bridge_remove,
};
static int __init serdes_bridge_init(void)
{
return platform_driver_register(&serdes_bridge_driver);
}
device_initcall(serdes_bridge_init);
static void __exit serdes_bridge_exit(void)
{
platform_driver_unregister(&serdes_bridge_driver);
}
module_exit(serdes_bridge_exit);
MODULE_AUTHOR("Luo Wei <lw@rock-chips.com>");
MODULE_DESCRIPTION("display bridge interface for different serdes");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:serdes-bridge");

View File

@@ -0,0 +1,391 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* serdes-core.c -- Device access for different serdes chips
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "core.h"
static const struct mfd_cell serdes_bu18tl82_devs[] = {
{
.name = "serdes-pinctrl",
.of_compatible = "rohm,bu18tl82-pinctrl",
},
{
.name = "serdes-bridge",
.of_compatible = "rohm,bu18tl82-bridge",
},
};
static const struct mfd_cell serdes_bu18rl82_devs[] = {
{
.name = "serdes-pinctrl",
.of_compatible = "rohm,bu18rl82-pinctrl",
},
{
.name = "serdes-bridge",
.of_compatible = "rohm,bu18rl82-bridge",
},
};
static const struct mfd_cell serdes_max96745_devs[] = {
{
.name = "serdes-pinctrl",
.of_compatible = "maxim,max96745-pinctrl",
},
{
.name = "serdes-bridge",
.of_compatible = "maxim,max96745-bridge",
},
};
static const struct mfd_cell serdes_max96755_devs[] = {
{
.name = "serdes-pinctrl",
.of_compatible = "maxim,max96755-pinctrl",
},
{
.name = "serdes-bridge",
.of_compatible = "maxim,max96755-bridge",
},
};
static const struct mfd_cell serdes_max96789_devs[] = {
{
.name = "serdes-pinctrl",
.of_compatible = "maxim,max96789-pinctrl",
},
{
.name = "serdes-bridge",
.of_compatible = "maxim,max96789-bridge",
},
};
static const struct mfd_cell serdes_max96752_devs[] = {
{
.name = "serdes-pinctrl",
.of_compatible = "maxim,max96752-pinctrl",
},
{
.name = "serdes-panel",
.of_compatible = "maxim,max96752-panel",
},
};
static const struct mfd_cell serdes_max96772_devs[] = {
{
.name = "serdes-pinctrl",
.of_compatible = "maxim,max96772-pinctrl",
},
{
.name = "serdes-panel",
.of_compatible = "maxim,max96772-panel",
},
};
static const struct mfd_cell serdes_rkx111_devs[] = {
{
.name = "serdes-pinctrl",
.of_compatible = "rockchip,rkx111-pinctrl",
},
{
.name = "serdes-bridge",
.of_compatible = "rockchip,rkx111-bridge",
},
};
static const struct mfd_cell serdes_rkx121_devs[] = {
{
.name = "serdes-pinctrl",
.of_compatible = "rockchip,rkx121-pinctrl",
},
{
.name = "serdes-bridge",
.of_compatible = "rockchip,rkx121-bridge",
},
};
static const struct mfd_cell serdes_nca9539_devs[] = {
{
.name = "serdes-pinctrl",
.of_compatible = "novo,nca9539-pinctrl",
},
};
/**
* serdes_reg_read: Read a single serdes register.
*
* @serdes: Device to read from.
* @reg: Register to read.
* @val: Data from register.
*/
int serdes_reg_read(struct serdes *serdes, unsigned int reg, unsigned int *val)
{
int ret;
ret = regmap_read(serdes->regmap, reg, val);
SERDES_DBG_I2C("%s %s Read Reg%04x %04x\n", __func__,
serdes->chip_data->name, reg, *val);
return ret;
}
EXPORT_SYMBOL_GPL(serdes_reg_read);
/**
* serdes_bulk_read: Read multiple serdes registers
*
* @serdes: Device to read from
* @reg: First register
* @count: Number of registers
* @buf: Buffer to fill.
*/
int serdes_bulk_read(struct serdes *serdes, unsigned int reg,
int count, u16 *buf)
{
int i = 0, ret = 0;
ret = regmap_bulk_read(serdes->regmap, reg, buf, count);
for (i = 0; i < count; i++) {
SERDES_DBG_I2C("%s %s %s Read Reg%04x %04x\n", __func__, dev_name(serdes->dev),
serdes->chip_data->name, reg + i, buf[i]);
}
return ret;
}
EXPORT_SYMBOL_GPL(serdes_bulk_read);
int serdes_bulk_write(struct serdes *serdes, unsigned int reg,
int count, void *src)
{
u16 *buf = src;
int i, ret;
WARN_ON(count <= 0);
mutex_lock(&serdes->io_lock);
for (i = 0; i < count; i++) {
SERDES_DBG_I2C("%s %s %s Write Reg%04x %04x\n", __func__, dev_name(serdes->dev),
serdes->chip_data->name, reg, buf[i]);
ret = regmap_write(serdes->regmap, reg, buf[i]);
if (ret != 0) {
mutex_unlock(&serdes->io_lock);
return ret;
}
}
mutex_unlock(&serdes->io_lock);
return 0;
}
EXPORT_SYMBOL_GPL(serdes_bulk_write);
/**
* serdes_multi_reg_write: Write many serdes register.
*
* @serdes: Device to write to.
* @regs: Registers to write to.
* @num_regs: Number of registers to write.
*/
int serdes_multi_reg_write(struct serdes *serdes, const struct reg_sequence *regs,
int num_regs)
{
int i, ret;
SERDES_DBG_I2C("%s %s %s num=%d\n", __func__, dev_name(serdes->dev),
serdes->chip_data->name, num_regs);
for (i = 0; i < num_regs; i++) {
SERDES_DBG_I2C("serdes %s Write Reg%04x %04x\n",
serdes->chip_data->name, regs[i].reg, regs[i].def);
}
ret = regmap_multi_reg_write(serdes->regmap, regs, num_regs);
return ret;
}
EXPORT_SYMBOL_GPL(serdes_multi_reg_write);
/**
* serdes_reg_write: Write a single serdes register.
*
* @serdes: Device to write to.
* @reg: Register to write to.
* @val: Value to write.
*/
int serdes_reg_write(struct serdes *serdes, unsigned int reg,
unsigned int val)
{
int ret;
SERDES_DBG_I2C("%s %s %s Write Reg%04x %04x)\n", __func__, dev_name(serdes->dev),
serdes->chip_data->name, reg, val);
ret = regmap_write(serdes->regmap, reg, val);
if (ret != 0)
return ret;
return ret;
}
EXPORT_SYMBOL_GPL(serdes_reg_write);
/**
* serdes_set_bits: Set the value of a bitfield in a serdes register
*
* @serdes: Device to write to.
* @reg: Register to write to.
* @mask: Mask of bits to set.
* @val: Value to set (unshifted)
*/
int serdes_set_bits(struct serdes *serdes, unsigned int reg,
unsigned int mask, unsigned int val)
{
int ret;
SERDES_DBG_I2C("%s %s %s Write Reg%04x %04x) mask=%04x\n", __func__,
dev_name(serdes->dev), serdes->chip_data->name, reg, val, mask);
ret = regmap_update_bits(serdes->regmap, reg, mask, val);
return ret;
}
EXPORT_SYMBOL_GPL(serdes_set_bits);
/*
* Instantiate the generic non-control parts of the device.
*/
int serdes_device_init(struct serdes *serdes)
{
struct serdes_chip_data *chip_data = serdes->chip_data;
int ret = 0;
const struct mfd_cell *serdes_devs = NULL;
int mfd_num = 0;
switch (chip_data->serdes_id) {
case ROHM_ID_BU18TL82:
serdes_devs = serdes_bu18tl82_devs;
mfd_num = ARRAY_SIZE(serdes_bu18tl82_devs);
break;
case ROHM_ID_BU18RL82:
serdes_devs = serdes_bu18rl82_devs;
mfd_num = ARRAY_SIZE(serdes_bu18rl82_devs);
break;
case MAXIM_ID_MAX96745:
serdes_devs = serdes_max96745_devs;
mfd_num = ARRAY_SIZE(serdes_max96745_devs);
break;
case MAXIM_ID_MAX96752:
serdes_devs = serdes_max96752_devs;
mfd_num = ARRAY_SIZE(serdes_max96752_devs);
break;
case MAXIM_ID_MAX96755:
serdes_devs = serdes_max96755_devs;
mfd_num = ARRAY_SIZE(serdes_max96755_devs);
break;
case MAXIM_ID_MAX96772:
serdes_devs = serdes_max96772_devs;
mfd_num = ARRAY_SIZE(serdes_max96772_devs);
break;
case MAXIM_ID_MAX96789:
serdes_devs = serdes_max96789_devs;
mfd_num = ARRAY_SIZE(serdes_max96789_devs);
break;
case ROCKCHIP_ID_RKX111:
serdes_devs = serdes_rkx111_devs;
mfd_num = ARRAY_SIZE(serdes_rkx111_devs);
break;
case ROCKCHIP_ID_RKX121:
serdes_devs = serdes_rkx121_devs;
mfd_num = ARRAY_SIZE(serdes_rkx121_devs);
break;
case NOVO_ID_NCA9539:
serdes_devs = serdes_nca9539_devs;
mfd_num = ARRAY_SIZE(serdes_nca9539_devs);
break;
default:
dev_info(serdes->dev, "%s: unknown device\n", __func__);
break;
}
ret = devm_mfd_add_devices(serdes->dev, PLATFORM_DEVID_AUTO, serdes_devs,
mfd_num, NULL, 0, NULL);
if (ret != 0) {
dev_err(serdes->dev, "Failed to add serdes children\n");
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(serdes_device_init);
int serdes_set_pinctrl_default(struct serdes *serdes)
{
int ret = 0;
if ((!IS_ERR(serdes->pinctrl_node)) && (!IS_ERR(serdes->pins_default))) {
ret = pinctrl_select_state(serdes->pinctrl_node, serdes->pins_default);
if (ret)
dev_err(serdes->dev, "could not set default pins\n");
SERDES_DBG_MFD("%s: name=%s\n", __func__, dev_name(serdes->dev));
}
return ret;
}
EXPORT_SYMBOL_GPL(serdes_set_pinctrl_default);
int serdes_set_pinctrl_sleep(struct serdes *serdes)
{
int ret = 0;
if ((!IS_ERR(serdes->pinctrl_node)) && (!IS_ERR(serdes->pins_sleep))) {
ret = pinctrl_select_state(serdes->pinctrl_node, serdes->pins_sleep);
if (ret)
dev_err(serdes->dev, "could not set sleep pins\n");
SERDES_DBG_MFD("%s: name=%s\n", __func__, dev_name(serdes->dev));
}
return ret;
}
EXPORT_SYMBOL_GPL(serdes_set_pinctrl_sleep);
int serdes_device_suspend(struct serdes *serdes)
{
int ret = 0;
if (!IS_ERR(serdes->vpower)) {
ret = regulator_disable(serdes->vpower);
if (ret) {
dev_err(serdes->dev, "fail to disable vpower regulator\n");
return ret;
}
}
return ret;
}
EXPORT_SYMBOL_GPL(serdes_device_suspend);
int serdes_device_resume(struct serdes *serdes)
{
int ret = 0;
if (!IS_ERR(serdes->vpower)) {
ret = regulator_enable(serdes->vpower);
if (ret) {
dev_err(serdes->dev, "fail to enable vpower regulator\n");
return ret;
}
}
return ret;
}
EXPORT_SYMBOL_GPL(serdes_device_resume);
void serdes_device_shutdown(struct serdes *serdes)
{
int ret = 0;
if ((!IS_ERR(serdes->pinctrl_node)) && (!IS_ERR(serdes->pins_sleep))) {
ret = pinctrl_select_state(serdes->pinctrl_node, serdes->pins_sleep);
if (ret)
dev_err(serdes->dev, "could not set sleep pins\n");
}
}
EXPORT_SYMBOL_GPL(serdes_device_shutdown);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,253 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* gpiolib support for different serdes chip
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*
*/
#include "core.h"
static int serdes_gpio_direction_in(struct gpio_chip *chip, unsigned int offset)
{
struct serdes_gpio *serdes_gpio = gpiochip_get_data(chip);
struct serdes *serdes = serdes_gpio->parent->parent;
int ret = 0;
if (serdes->chip_data->gpio_ops->direction_input)
ret = serdes->chip_data->gpio_ops->direction_input(serdes, offset);
SERDES_DBG_MFD("%s: %s %s gpio=%d\n", __func__, dev_name(serdes->dev),
serdes->chip_data->name, offset);
return ret;
}
static int serdes_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct serdes_gpio *serdes_gpio = gpiochip_get_data(chip);
struct serdes *serdes = serdes_gpio->parent->parent;
int ret = 0;
if (serdes->chip_data->gpio_ops->get_level)
ret = serdes->chip_data->gpio_ops->get_level(serdes, offset);
SERDES_DBG_MFD("%s: %s %s gpio=%d\n", __func__, dev_name(serdes->dev),
serdes->chip_data->name, offset);
return ret;
}
static void serdes_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct serdes_gpio *serdes_gpio = gpiochip_get_data(chip);
struct serdes *serdes = serdes_gpio->parent->parent;
int ret = 0;
if (serdes->chip_data->gpio_ops->set_level)
ret = serdes->chip_data->gpio_ops->set_level(serdes, offset, value);
SERDES_DBG_MFD("%s: %s %s gpio=%d,val=%d\n", __func__, dev_name(serdes->dev),
serdes->chip_data->name, offset, value);
}
static int serdes_gpio_direction_out(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct serdes_gpio *serdes_gpio = gpiochip_get_data(chip);
struct serdes *serdes = serdes_gpio->parent->parent;
int ret = 0;
if (serdes->chip_data->gpio_ops->direction_output)
ret = serdes->chip_data->gpio_ops->direction_output(serdes, offset, value);
SERDES_DBG_MFD("%s: %s %s gpio=%d,val=%d\n", __func__, dev_name(serdes->dev),
serdes->chip_data->name, offset, value);
return ret;
}
static int serdes_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
{
struct serdes_gpio *serdes_gpio = gpiochip_get_data(chip);
struct serdes *serdes = serdes_gpio->parent->parent;
int ret = 0;
if (serdes->chip_data->gpio_ops->to_irq)
ret = serdes->chip_data->gpio_ops->to_irq(serdes, offset);
SERDES_DBG_MFD("%s: %s %s gpio=%d\n", __func__, dev_name(serdes->dev),
serdes->chip_data->name, offset);
return ret;
}
static int serdes_set_config(struct gpio_chip *chip, unsigned int offset,
unsigned long config)
{
struct serdes_gpio *serdes_gpio = gpiochip_get_data(chip);
struct serdes *serdes = serdes_gpio->parent->parent;
//int param = pinconf_to_config_param(config);
int ret = 0;
//int gpio = offset;
if (serdes->chip_data->gpio_ops->set_config)
ret = serdes->chip_data->gpio_ops->set_config(serdes, offset, config);
SERDES_DBG_MFD("%s: %s %s gpio=%d,config=%d\n", __func__,
dev_name(serdes->dev),
serdes->chip_data->name, offset, pinconf_to_config_param(config));
return ret;
}
#ifdef CONFIG_DEBUG_FS
static void serdes_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
struct serdes_gpio *serdes_gpio = gpiochip_get_data(chip);
struct serdes *serdes = serdes_gpio->parent->parent;
int i = 0;
int ret = 0;
for (i = 0; i < chip->ngpio; i++) {
int gpio = i + chip->base;
const char *label, *level;
/* We report the GPIO even if it's not requested since
* we're also reporting things like alternate
* functions which apply even when the GPIO is not in
* use as a GPIO.
*/
label = gpiochip_is_requested(chip, i);
if (!label)
label = "Unrequested";
seq_printf(s, " %s-gpio-%02d ", label, gpio);
if (serdes->chip_data->gpio_ops->get_level)
ret = serdes->chip_data->gpio_ops->get_level(serdes, i);
switch (ret) {
case SERDES_GPIO_LEVEL_HIGH:
level = "level-high";
break;
case SERDES_GPIO_LEVEL_LOW:
level = "level-low";
break;
default:
level = "invalid level";
break;
}
seq_printf(s, " %s\n", level);
}
}
#else
#define serdes_gpio_dbg_show NULL
#endif
static const struct gpio_chip serdes_gpio_chip = {
.owner = THIS_MODULE,
.request = gpiochip_generic_request,
.free = gpiochip_generic_free,
.direction_input = serdes_gpio_direction_in,
.direction_output = serdes_gpio_direction_out,
.get = serdes_gpio_get,
.set = serdes_gpio_set,
.set_config = serdes_set_config,
.to_irq = serdes_gpio_to_irq,
.dbg_show = serdes_gpio_dbg_show,
.can_sleep = true,
};
static int serdes_gpio_probe(struct platform_device *pdev)
{
struct serdes_pinctrl *serdes_pinctrl = dev_get_drvdata(pdev->dev.parent);
struct serdes *serdes = serdes_pinctrl->parent;
struct serdes_chip_data *chip_data = serdes->chip_data;
struct device *dev = &pdev->dev;
struct serdes_gpio *serdes_gpio;
const char *list_name = "gpio-ranges";
struct of_phandle_args of_args;
int ret;
serdes_gpio = devm_kzalloc(&pdev->dev, sizeof(*serdes_gpio),
GFP_KERNEL);
if (serdes_gpio == NULL)
return -ENOMEM;
ret = of_parse_phandle_with_fixed_args(dev->of_node, list_name, 3, 0, &of_args);
if (ret) {
dev_err(dev, "Unable to parse %s list property\n",
list_name);
return ret;
}
serdes_pinctrl->gpio = serdes_gpio;
serdes_gpio->dev = dev;
serdes_gpio->parent = serdes_pinctrl;
serdes_gpio->gpio_chip = serdes_gpio_chip;
serdes_gpio->gpio_chip.parent = pdev->dev.parent;
if (of_args.args[2]) {
serdes_gpio->gpio_chip.base = of_args.args[1];
serdes_gpio->gpio_chip.ngpio = of_args.args[2];
} else {
serdes_gpio->gpio_chip.base = -1;
serdes_gpio->gpio_chip.ngpio = 8;
}
#ifdef CONFIG_OF_GPIO
serdes_gpio->gpio_chip.of_node = serdes_gpio->dev->of_node;
#endif
serdes_gpio->gpio_chip.label = kasprintf(GFP_KERNEL, "%s-gpio", chip_data->name);
/* Add gpiochip */
ret = devm_gpiochip_add_data(&pdev->dev, &serdes_gpio->gpio_chip,
serdes_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register serdes gpiochip, %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, serdes_gpio);
dev_info(serdes_gpio->dev->parent->parent,
"%s serdes_gpio_probe successful, base=%d, ngpio=%d\n",
serdes->chip_data->name,
serdes_gpio->gpio_chip.base, serdes_gpio->gpio_chip.ngpio);
return ret;
}
static const struct of_device_id serdes_gpio_of_match[] = {
{ .compatible = "rohm,bu18tl82-gpio", },
{ .compatible = "rohm,bu18rl82-gpio", },
{ .compatible = "maxim,max96745-gpio", },
{ .compatible = "maxim,max96752-gpio", },
{ .compatible = "maxim,max96755-gpio", },
{ .compatible = "maxim,max96772-gpio", },
{ .compatible = "rockchip,rkx111-gpio", },
{ .compatible = "rockchip,rkx121-gpio", },
{ .compatible = "novo,nca9539-gpio", },
{ }
};
static struct platform_driver serdes_gpio_driver = {
.driver = {
.name = "serdes-gpio",
.of_match_table = of_match_ptr(serdes_gpio_of_match),
},
.probe = serdes_gpio_probe,
};
static int __init serdes_gpio_init(void)
{
return platform_driver_register(&serdes_gpio_driver);
}
device_initcall(serdes_gpio_init);
static void __exit serdes_gpio_exit(void)
{
platform_driver_unregister(&serdes_gpio_driver);
}
module_exit(serdes_gpio_exit);
MODULE_AUTHOR("Luo Wei <lw@rock-chips.com>");
MODULE_DESCRIPTION("display bridge interface for different serdes");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:serdes-bridge");

View File

@@ -0,0 +1,337 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* serdes-i2c.c -- I2C access for different serdes chips
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "core.h"
int serdes_i2c_set_sequence(struct serdes *serdes)
{
struct device *dev = serdes->dev;
int i, ret = 0;
unsigned int def = 0;
for (i = 0; i < serdes->serdes_init_seq->reg_seq_cnt; i++) {
if (serdes->serdes_init_seq->reg_sequence[i].reg == 0xffff) {
SERDES_DBG_MFD("%s: delay 0x%04x us\n", __func__,
serdes->serdes_init_seq->reg_sequence[i].def);
udelay(serdes->serdes_init_seq->reg_sequence[i].def);
continue;
}
ret = serdes_reg_write(serdes,
serdes->serdes_init_seq->reg_sequence[i].reg,
serdes->serdes_init_seq->reg_sequence[i].def);
if (ret < 0) {
dev_err(serdes->dev,
"failed to write register %04x, ret %d, write again now\n",
serdes->serdes_init_seq->reg_sequence[i].reg, ret);
ret = serdes_reg_write(serdes,
serdes->serdes_init_seq->reg_sequence[i].reg,
serdes->serdes_init_seq->reg_sequence[i].def);
}
serdes_reg_read(serdes, serdes->serdes_init_seq->reg_sequence[i].reg, &def);
if ((def != serdes->serdes_init_seq->reg_sequence[i].def) || (ret < 0)) {
/* if read value != write value then write again */
dev_err(dev, "read %04x %04x != %04x\n",
serdes->serdes_init_seq->reg_sequence[i].reg,
def, serdes->serdes_init_seq->reg_sequence[i].def);
serdes_reg_write(serdes,
serdes->serdes_init_seq->reg_sequence[i].reg,
serdes->serdes_init_seq->reg_sequence[i].def);
}
}
dev_info(dev, "serdes %s sequence_init\n", serdes->chip_data->name);
return ret;
}
EXPORT_SYMBOL_GPL(serdes_i2c_set_sequence);
static void serdes_mfd_work(struct work_struct *work)
{
struct serdes *serdes = container_of(work, struct serdes, mfd_delay_work.work);
mutex_lock(&serdes->wq_lock);
serdes_device_init(serdes);
mutex_unlock(&serdes->wq_lock);
}
static const unsigned int serdes_cable[] = {
EXTCON_JACK_VIDEO_OUT,
EXTCON_NONE,
};
static int serdes_parse_init_seq(struct device *dev, const u16 *data,
int length, struct serdes_init_seq *seq)
{
struct reg_sequence *reg_sequence;
u16 *buf, *d;
unsigned int i, cnt;
if (!seq)
return -EINVAL;
buf = devm_kmemdup(dev, data, length, GFP_KERNEL);
if (!buf)
return -ENOMEM;
d = buf;
cnt = length / 4;
seq->reg_seq_cnt = cnt;
seq->reg_sequence = devm_kcalloc(dev, cnt, sizeof(struct reg_sequence), GFP_KERNEL);
if (!seq->reg_sequence)
return -ENOMEM;
for (i = 0; i < cnt; i++) {
reg_sequence = &seq->reg_sequence[i];
reg_sequence->reg = get_unaligned_be16(&d[0]);
reg_sequence->def = get_unaligned_be16(&d[1]);
d += 2;
}
return 0;
}
static int serdes_get_init_seq(struct serdes *serdes)
{
struct device *dev = serdes->dev;
struct device_node *np = dev->of_node;
const void *data;
int err, len, ret = 0;
data = of_get_property(np, "serdes-init-sequence", &len);
if (!data) {
dev_err(dev, "failed to get serdes-init-sequence\n");
return -EINVAL;
}
serdes->serdes_init_seq = devm_kzalloc(dev, sizeof(*serdes->serdes_init_seq),
GFP_KERNEL);
if (!serdes->serdes_init_seq)
return -ENOMEM;
err = serdes_parse_init_seq(dev, data, len, serdes->serdes_init_seq);
if (err) {
dev_err(dev, "failed to parse serdes-init-sequence\n");
return err;
}
/* init ser register(not des register) more early if uboot logo disabled */
serdes->route_enable = of_property_read_bool(dev->of_node, "route-enable");
if ((!serdes->route_enable) && (serdes->chip_data->serdes_type == TYPE_SER))
ret = serdes_i2c_set_sequence(serdes);
return ret;
}
static int serdes_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct serdes *serdes;
int ret;
serdes = devm_kzalloc(&client->dev, sizeof(struct serdes), GFP_KERNEL);
if (serdes == NULL)
return -ENOMEM;
serdes->dev = dev;
serdes->chip_data = (struct serdes_chip_data *)of_device_get_match_data(dev);
i2c_set_clientdata(client, serdes);
dev_info(dev, "serdes %s probe start\n", serdes->chip_data->name);
serdes->type = serdes->chip_data->serdes_type;
serdes->regmap = devm_regmap_init_i2c(client, serdes->chip_data->regmap_config);
if (IS_ERR(serdes->regmap)) {
ret = PTR_ERR(serdes->regmap);
dev_err(serdes->dev, "Failed to allocate serdes register map: %d\n",
ret);
return ret;
}
serdes->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
if (IS_ERR(serdes->reset_gpio))
return dev_err_probe(dev, PTR_ERR(serdes->reset_gpio),
"failed to acquire serdes reset gpio\n");
serdes->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_ASIS);
if (IS_ERR(serdes->enable_gpio))
return dev_err_probe(dev, PTR_ERR(serdes->enable_gpio),
"failed to acquire serdes enable gpio\n");
serdes->vpower = devm_regulator_get_optional(dev, "vpower");
if (IS_ERR(serdes->vpower)) {
if (PTR_ERR(serdes->vpower) != -ENODEV)
return PTR_ERR(serdes->vpower);
dev_info(dev, "no vpower regulator found\n");
}
if (!IS_ERR(serdes->vpower)) {
ret = regulator_enable(serdes->vpower);
if (ret) {
dev_err(dev, "fail to enable vpower regulator\n");
return ret;
}
}
serdes->extcon = devm_extcon_dev_allocate(dev, serdes_cable);
if (IS_ERR(serdes->extcon))
return dev_err_probe(dev, PTR_ERR(serdes->extcon),
"failed to allocate serdes extcon device\n");
ret = devm_extcon_dev_register(dev, serdes->extcon);
if (ret)
return dev_err_probe(dev, ret,
"failed to register serdes extcon device\n");
ret = serdes_get_init_seq(serdes);
if (ret)
return dev_err_probe(dev, ret,
"failed to write serdes register with i2c\n");
mutex_init(&serdes->io_lock);
dev_set_drvdata(serdes->dev, serdes);
ret = serdes_irq_init(serdes);
if (ret != 0) {
serdes_irq_exit(serdes);
return ret;
}
serdes->use_delay_work = of_property_read_bool(dev->of_node, "use-delay-work");
if (serdes->use_delay_work) {
serdes->mfd_wq = alloc_ordered_workqueue("%s",
WQ_MEM_RECLAIM | WQ_FREEZABLE,
"serdes-mfd-wq");
mutex_init(&serdes->wq_lock);
INIT_DELAYED_WORK(&serdes->mfd_delay_work, serdes_mfd_work);
queue_delayed_work(serdes->mfd_wq, &serdes->mfd_delay_work, msecs_to_jiffies(300));
SERDES_DBG_MFD("%s: use_delay_work=%d\n", __func__, serdes->use_delay_work);
} else {
ret = serdes_device_init(serdes);
SERDES_DBG_MFD("%s: use_delay_work=%d\n", __func__, serdes->use_delay_work);
}
dev_info(dev, "serdes %s serdes_i2c_probe successful version %s\n",
serdes->chip_data->name, MFD_SERDES_DISPLAY_VERSION);
return ret;
}
static int serdes_i2c_prepare(struct device *dev)
{
return 0;
}
static void serdes_i2c_complete(struct device *dev)
{
struct serdes *serdes = dev_get_drvdata(dev);
if (serdes->chip_data->serdes_type == TYPE_SER)
serdes_i2c_set_sequence(serdes);
SERDES_DBG_MFD("%s: name=%s\n", __func__, dev_name(serdes->dev));
}
static int serdes_i2c_suspend(struct device *dev)
{
struct serdes *serdes = dev_get_drvdata(dev);
serdes_device_suspend(serdes);
SERDES_DBG_MFD("%s: name=%s\n", __func__, dev_name(serdes->dev));
return 0;
}
static int serdes_i2c_resume(struct device *dev)
{
struct serdes *serdes = dev_get_drvdata(dev);
if (serdes->chip_data->serdes_type == TYPE_OTHER)
serdes_i2c_set_sequence(serdes);
serdes_device_resume(serdes);
SERDES_DBG_MFD("%s: name=%s\n", __func__, dev_name(serdes->dev));
return 0;
}
static int serdes_i2c_poweroff(struct device *dev)
{
struct serdes *serdes = dev_get_drvdata(dev);
serdes_device_shutdown(serdes);
return 0;
}
static const struct of_device_id serdes_of_match[] = {
#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18TL82)
{ .compatible = "rohm,bu18tl82", .data = &serdes_bu18tl82_data },
#endif
#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROHM_BU18RL82)
{ .compatible = "rohm,bu18rl82", .data = &serdes_bu18rl82_data },
#endif
#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96745)
{ .compatible = "maxim,max96745", .data = &serdes_max96745_data },
#endif
#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96752)
{ .compatible = "maxim,max96752", .data = &serdes_max96752_data },
#endif
#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96755)
{ .compatible = "maxim,max96755", .data = &serdes_max96755_data },
#endif
#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_MAXIM_MAX96772)
{ .compatible = "maxim,max96772", .data = &serdes_max96772_data },
#endif
#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX111)
{ .compatible = "rockchip,rkx111", .data = &serdes_rkx111_data },
#endif
#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_ROCKCHIP_RKX121)
{ .compatible = "rockchip,rkx121", .data = &serdes_rkx121_data },
#endif
#if IS_ENABLED(CONFIG_SERDES_DISPLAY_CHIP_NOVO_NCA9539)
{ .compatible = "novo,nca9539", .data = &serdes_nca9539_data },
#endif
{ }
};
static const struct dev_pm_ops serdes_pm_ops = {
.prepare = serdes_i2c_prepare,
.complete = serdes_i2c_complete,
.suspend = serdes_i2c_suspend,
.resume = serdes_i2c_resume,
.poweroff = serdes_i2c_poweroff,
};
static struct i2c_driver serdes_i2c_driver = {
.driver = {
.name = "serdes",
.pm = &serdes_pm_ops,
.of_match_table = of_match_ptr(serdes_of_match),
},
.probe = serdes_i2c_probe,
};
static int __init serdes_i2c_init(void)
{
int ret;
ret = i2c_add_driver(&serdes_i2c_driver);
if (ret != 0)
pr_err("Failed to register serdes I2C driver: %d\n", ret);
return ret;
}
subsys_initcall(serdes_i2c_init);
MODULE_AUTHOR("Luo Wei <lw@rock-chips.com>");
MODULE_DESCRIPTION("display i2c interface for different serdes");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:serdes-i2c");

View File

@@ -0,0 +1,109 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* serdes-irq.c -- Interrupt controller support for different serdes chips
*
* Copyright 2009 Wolfson Microelectronics PLC.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "core.h"
static irqreturn_t serdes_bridge_lock_irq_handler(int irq, void *arg)
{
struct serdes *serdes = arg;
int ret = 0;
if (serdes->chip_data->irq_ops->lock_handle)
ret = serdes->chip_data->irq_ops->lock_handle(serdes);
if (extcon_get_state(serdes->extcon, EXTCON_JACK_VIDEO_OUT))
atomic_set(&serdes->serdes_bridge->triggered, 1);
SERDES_DBG_MFD("%s: ret=%d\n", __func__, ret);
return IRQ_HANDLED;
}
static irqreturn_t serdes_bridge_err_irq_handler(int irq, void *arg)
{
struct serdes *serdes = arg;
int ret = 0;
if (serdes->chip_data->irq_ops->err_handle)
ret = serdes->chip_data->irq_ops->err_handle(serdes);
SERDES_DBG_MFD("%s: ret=%d\n", __func__, ret);
return IRQ_HANDLED;
}
int serdes_irq_init(struct serdes *serdes)
{
int ret;
mutex_init(&serdes->irq_lock);
/* lock irq */
serdes->lock_gpio = devm_gpiod_get_optional(serdes->dev, "lock", GPIOD_IN);
if (IS_ERR(serdes->lock_gpio))
return dev_err_probe(serdes->dev, PTR_ERR(serdes->lock_gpio),
"failed to get serdes lock GPIO\n");
if (serdes->lock_gpio) {
serdes->lock_irq = gpiod_to_irq(serdes->lock_gpio);
if (serdes->lock_irq < 0)
return serdes->lock_irq;
SERDES_DBG_MFD("%s %s lock_irq=%d\n", __func__,
serdes->chip_data->name, serdes->lock_irq);
ret = devm_request_threaded_irq(serdes->dev, serdes->lock_irq, NULL,
serdes_bridge_lock_irq_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(serdes->dev), serdes);
if (ret)
return dev_err_probe(serdes->dev, ret,
"failed to request serdes lock IRQ\n");
}
/* error irq */
serdes->err_gpio = devm_gpiod_get_optional(serdes->dev, "err", GPIOD_IN);
if (IS_ERR(serdes->err_gpio))
return dev_err_probe(serdes->dev, PTR_ERR(serdes->err_gpio),
"failed to get serdes err GPIO\n");
if (serdes->err_gpio) {
serdes->err_irq = gpiod_to_irq(serdes->err_gpio);
if (serdes->err_irq < 0)
return serdes->err_irq;
SERDES_DBG_MFD("%s %s err_irq=%d\n", __func__,
serdes->chip_data->name, serdes->err_irq);
ret = devm_request_threaded_irq(serdes->dev, serdes->err_irq, NULL,
serdes_bridge_err_irq_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(serdes->dev), serdes);
if (ret)
return dev_err_probe(serdes->dev, ret, "failed to request err IRQ\n");
}
SERDES_DBG_MFD("serdes %s serdes_irq_init successful, ret=%d\n",
serdes->chip_data->name, ret);
return 0;
}
EXPORT_SYMBOL_GPL(serdes_irq_init);
void serdes_irq_exit(struct serdes *serdes)
{
if (serdes->lock_irq)
devm_free_irq(serdes->dev, serdes->lock_irq, serdes);
if (serdes->err_irq)
devm_free_irq(serdes->dev, serdes->err_irq, serdes);
}
EXPORT_SYMBOL_GPL(serdes_irq_exit);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,246 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* serdes-panel.c -- drm panel access for different serdes chips
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "core.h"
static inline struct serdes_panel *to_serdes_panel(struct drm_panel *panel)
{
return container_of(panel, struct serdes_panel, panel);
}
static int serdes_panel_prepare(struct drm_panel *panel)
{
struct serdes_panel *serdes_panel = to_serdes_panel(panel);
struct serdes *serdes = serdes_panel->parent;
int ret = 0;
if (serdes->chip_data->panel_ops && serdes->chip_data->panel_ops->init)
ret = serdes->chip_data->panel_ops->init(serdes);
if (serdes->chip_data->serdes_type == TYPE_DES)
serdes_i2c_set_sequence(serdes);
if (serdes->chip_data->panel_ops && serdes->chip_data->panel_ops->prepare)
ret = serdes->chip_data->panel_ops->prepare(serdes);
serdes_set_pinctrl_default(serdes);
SERDES_DBG_MFD("%s: %s\n", __func__, serdes->chip_data->name);
return ret;
}
static int serdes_panel_unprepare(struct drm_panel *panel)
{
struct serdes_panel *serdes_panel = to_serdes_panel(panel);
struct serdes *serdes = serdes_panel->parent;
int ret = 0;
if (serdes->chip_data->panel_ops && serdes->chip_data->panel_ops->unprepare)
ret = serdes->chip_data->panel_ops->unprepare(serdes);
serdes_set_pinctrl_sleep(serdes);
SERDES_DBG_MFD("%s: %s\n", __func__, serdes->chip_data->name);
return ret;
}
static int serdes_panel_enable(struct drm_panel *panel)
{
struct serdes_panel *serdes_panel = to_serdes_panel(panel);
struct serdes *serdes = serdes_panel->parent;
int ret = 0;
if (serdes->chip_data->panel_ops && serdes->chip_data->panel_ops->enable)
ret = serdes->chip_data->panel_ops->enable(serdes);
backlight_enable(serdes_panel->backlight);
SERDES_DBG_MFD("%s: %s\n", __func__, serdes->chip_data->name);
return ret;
}
static int serdes_panel_disable(struct drm_panel *panel)
{
struct serdes_panel *serdes_panel = to_serdes_panel(panel);
struct serdes *serdes = serdes_panel->parent;
int ret = 0;
if (serdes->chip_data->panel_ops && serdes->chip_data->panel_ops->disable)
ret = serdes->chip_data->panel_ops->disable(serdes);
backlight_disable(serdes_panel->backlight);
SERDES_DBG_MFD("%s: %s\n", __func__, serdes->chip_data->name);
return ret;
}
static int serdes_panel_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct serdes_panel *serdes_panel = to_serdes_panel(panel);
struct serdes *serdes = serdes_panel->parent;
struct drm_display_mode *mode;
u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
int ret = 0;
connector->display_info.width_mm = serdes_panel->width_mm; //323; //346;
connector->display_info.height_mm = serdes_panel->height_mm; //182; //194;
drm_display_info_set_bus_formats(&connector->display_info, &bus_format, 1);
mode = drm_mode_duplicate(connector->dev, &serdes_panel->mode);
mode->width_mm = serdes_panel->width_mm; //323; //346;
mode->height_mm = serdes_panel->height_mm; //182; //194;
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_set_name(mode);
drm_mode_probed_add(connector, mode);
if (serdes->chip_data->panel_ops && serdes->chip_data->panel_ops->get_modes)
ret = serdes->chip_data->panel_ops->get_modes(serdes);
SERDES_DBG_MFD("%s: %s node=%s\n", __func__,
serdes->chip_data->name, panel->dev->of_node->name);
return ret;
}
static const struct drm_panel_funcs serdes_panel_funcs = {
.prepare = serdes_panel_prepare,
.unprepare = serdes_panel_unprepare,
.enable = serdes_panel_enable,
.disable = serdes_panel_disable,
.get_modes = serdes_panel_get_modes,
};
static int serdes_panel_parse_dt(struct serdes_panel *serdes_panel)
{
struct device *dev = serdes_panel->dev;
struct display_timing dt;
struct videomode vm;
int ret, len;
unsigned int panel_size[2] = {320, 180};
serdes_panel->width_mm = panel_size[0];
serdes_panel->height_mm = panel_size[1];
if (of_find_property(dev->of_node, "panel-size", &len)) {
len /= sizeof(unsigned int);
ret = of_property_read_u32_array(dev->of_node, "panel-size",
panel_size, len);
if (!ret) {
serdes_panel->width_mm = panel_size[0];
serdes_panel->height_mm = panel_size[1];
}
}
dev_info(dev, "panle size %dx%d\n",
serdes_panel->width_mm, serdes_panel->height_mm);
ret = of_get_display_timing(dev->of_node, "panel-timing", &dt);
if (ret < 0) {
dev_err(dev, "%pOF:serdes no panel-timing node found\n", dev->of_node);
return ret;
}
videomode_from_timing(&dt, &vm);
drm_display_mode_from_videomode(&vm, &serdes_panel->mode);
return 0;
}
static int serdes_panel_probe(struct platform_device *pdev)
{
struct serdes *serdes = dev_get_drvdata(pdev->dev.parent);
struct device *dev = &pdev->dev;
struct serdes_panel *serdes_panel;
int ret;
serdes_panel = devm_kzalloc(dev, sizeof(*serdes_panel), GFP_KERNEL);
if (!serdes_panel)
return -ENOMEM;
serdes->serdes_panel = serdes_panel;
serdes_panel->dev = dev;
serdes_panel->parent = dev_get_drvdata(dev->parent);
platform_set_drvdata(pdev, serdes_panel);
serdes_panel->regmap = dev_get_regmap(dev->parent, NULL);
if (!serdes_panel->regmap)
return dev_err_probe(dev, -ENODEV, "failed to get serdes regmap\n");
ret = serdes_panel_parse_dt(serdes_panel);
if (ret)
return dev_err_probe(dev, ret, "failed to parse serdes DT\n");
serdes_panel->backlight = devm_of_find_backlight(dev);
if (IS_ERR(serdes_panel->backlight))
return dev_err_probe(dev, PTR_ERR(serdes_panel->backlight),
"failed to get serdes backlight\n");
if (serdes_panel->parent->chip_data->connector_type) {
drm_panel_init(&serdes_panel->panel, dev, &serdes_panel_funcs,
serdes_panel->parent->chip_data->connector_type);
} else {
drm_panel_init(&serdes_panel->panel, dev, &serdes_panel_funcs,
DRM_MODE_CONNECTOR_LVDS);
}
drm_panel_add(&serdes_panel->panel);
dev_info(dev, "serdes %s serdes_panel_probe successful\n", serdes->chip_data->name);
return 0;
}
static int serdes_panel_remove(struct platform_device *pdev)
{
struct serdes_panel *serdes_panel = platform_get_drvdata(pdev);
drm_panel_remove(&serdes_panel->panel);
return 0;
}
static const struct of_device_id serdes_panel_of_match[] = {
{ .compatible = "rohm,bu18tl82-panel" },
{ .compatible = "rohm,bu18rl82-panel" },
{ .compatible = "maxim,max96752-panel" },
{ .compatible = "maxim,max96772-panel" },
{ .compatible = "rockchip,rkx121-panel" },
{ }
};
static struct platform_driver serdes_panel_driver = {
.driver = {
.name = "serdes-panel",
.of_match_table = of_match_ptr(serdes_panel_of_match),
},
.probe = serdes_panel_probe,
.remove = serdes_panel_remove,
};
static int __init serdes_panel_init(void)
{
return platform_driver_register(&serdes_panel_driver);
}
device_initcall(serdes_panel_init);
static void __exit serdes_panel_exit(void)
{
platform_driver_unregister(&serdes_panel_driver);
}
module_exit(serdes_panel_exit);
MODULE_AUTHOR("Luo Wei <lw@rock-chips.com>");
MODULE_DESCRIPTION("display panel interface for different serdes");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:serdes-panel");

View File

@@ -0,0 +1,393 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* serdes-pinctrl.c -- serdes pin control driver.
*
* Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "core.h"
static const struct mfd_cell serdes_gpio_bu18tl82_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "rohm,bu18tl82-gpio",
},
};
static const struct mfd_cell serdes_gpio_bu18rl82_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "rohm,bu18rl82-gpio",
},
};
static const struct mfd_cell serdes_gpio_max96745_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "maxim,max96745-gpio",
},
};
static const struct mfd_cell serdes_gpio_max96755_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "maxim,max96755-gpio",
},
};
static const struct mfd_cell serdes_gpio_max96789_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "maxim,max96789-gpio",
},
};
static const struct mfd_cell serdes_gpio_max96752_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "maxim,max96752-gpio",
},
};
static const struct mfd_cell serdes_gpio_max96772_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "maxim,max96772-gpio",
},
};
static const struct mfd_cell serdes_gpio_rkx111_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "rockchip,rkx111-gpio",
},
};
static const struct mfd_cell serdes_gpio_rkx121_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "rockchip,rkx121-gpio",
},
};
static const struct mfd_cell serdes_gpio_nca9539_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "novo,nca9539-gpio",
},
};
static int serdes_pinmux_set_mux(struct pinctrl_dev *pctldev,
unsigned int function, unsigned int group)
{
struct serdes_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
struct serdes *serdes = pinctrl->parent;
int ret = 0;
if (serdes->chip_data->pinctrl_ops->set_mux)
ret = serdes->chip_data->pinctrl_ops->set_mux(serdes, function, group);
SERDES_DBG_MFD("%s: %s function=%d,group=%d\n", __func__,
serdes->chip_data->name, function, group);
return ret;
}
static int serdes_pinconf_get(struct pinctrl_dev *pctldev,
unsigned int pin, unsigned long *config)
{
struct serdes_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
//enum pin_config_param param = pinconf_to_config_param(*config);
struct serdes *serdes = pinctrl->parent;
int ret = 0;
if (serdes->chip_data->pinctrl_ops->pin_config_get)
ret = serdes->chip_data->pinctrl_ops->pin_config_get(serdes,
pin - pinctrl->pin_base,
config);
SERDES_DBG_MFD("%s: %s pin=%d,config=%d\n", __func__,
serdes->chip_data->name,
pin - pinctrl->pin_base, pinconf_to_config_param(*config));
return ret;
}
static int serdes_pinconf_set(struct pinctrl_dev *pctldev,
unsigned int pin, unsigned long *configs,
unsigned int num_configs)
{
struct serdes_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
//enum pin_config_param param = pinconf_to_config_param(*configs);
struct serdes *serdes = pinctrl->parent;
int ret = 0;
if (serdes->chip_data->pinctrl_ops->pin_config_set)
ret = serdes->chip_data->pinctrl_ops->pin_config_set(serdes,
pin - pinctrl->pin_base,
configs, num_configs);
SERDES_DBG_MFD("%s: %s pin=%d,config=%d\n", __func__, serdes->chip_data->name,
pin - pinctrl->pin_base, pinconf_to_config_param(*configs));
return ret;
}
static const struct pinconf_ops serdes_pinconf_ops = {
.pin_config_get = serdes_pinconf_get,
.pin_config_set = serdes_pinconf_set,
};
static const struct pinmux_ops serdes_pinmux_ops = {
.get_functions_count = pinmux_generic_get_function_count,
.get_function_name = pinmux_generic_get_function_name,
.get_function_groups = pinmux_generic_get_function_groups,
.set_mux = serdes_pinmux_set_mux,
};
static const struct pinctrl_ops serdes_pinctrl_ops = {
.get_groups_count = pinctrl_generic_get_group_count,
.get_group_name = pinctrl_generic_get_group_name,
.get_group_pins = pinctrl_generic_get_group_pins,
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
.dt_free_map = pinconf_generic_dt_free_map,
};
static int serdes_pinctrl_gpio_init(struct serdes *serdes)
{
struct serdes_chip_data *chip_data = serdes->chip_data;
struct serdes_pinctrl *pinctrl = serdes->pinctrl;
const struct mfd_cell *serdes_devs = NULL;
int ret = 0;
int mfd_num = 0;
switch (chip_data->serdes_id) {
case ROHM_ID_BU18TL82:
serdes_devs = serdes_gpio_bu18tl82_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_bu18tl82_devs);
break;
case ROHM_ID_BU18RL82:
serdes_devs = serdes_gpio_bu18rl82_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_bu18rl82_devs);
break;
case MAXIM_ID_MAX96745:
serdes_devs = serdes_gpio_max96745_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_max96745_devs);
break;
case MAXIM_ID_MAX96752:
serdes_devs = serdes_gpio_max96752_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_max96752_devs);
break;
case MAXIM_ID_MAX96755:
serdes_devs = serdes_gpio_max96755_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_max96755_devs);
break;
case MAXIM_ID_MAX96772:
serdes_devs = serdes_gpio_max96772_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_max96772_devs);
break;
case MAXIM_ID_MAX96789:
serdes_devs = serdes_gpio_max96789_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_max96789_devs);
break;
case ROCKCHIP_ID_RKX111:
serdes_devs = serdes_gpio_rkx111_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_rkx111_devs);
break;
case ROCKCHIP_ID_RKX121:
serdes_devs = serdes_gpio_rkx121_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_rkx121_devs);
break;
case NOVO_ID_NCA9539:
serdes_devs = serdes_gpio_nca9539_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_nca9539_devs);
break;
default:
dev_info(serdes->dev, "%s: unknown device\n", __func__);
break;
}
ret = devm_mfd_add_devices(pinctrl->dev, PLATFORM_DEVID_AUTO, serdes_devs,
mfd_num, NULL, 0, NULL);
if (ret != 0)
dev_err(pinctrl->dev, "Failed to add serdes children\n");
return ret;
}
static int serdes_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct serdes *serdes = dev_get_drvdata(pdev->dev.parent);
const struct serdes_chip_data *chip_data = serdes->chip_data;
struct serdes_pinctrl *serdes_pinctrl;
struct pinctrl_desc *pinctrl_desc;
const struct serdes_chip_pinctrl_info *pinctrl_info;
struct device_node *child;
const char *list_name = "gpio-ranges";
struct of_phandle_args of_args;
int pin_base = 0;
int i, j, ret;
if (!serdes->dev)
return -1;
pinctrl_info = chip_data->pinctrl_info;
serdes_pinctrl = devm_kzalloc(dev, sizeof(*serdes_pinctrl), GFP_KERNEL);
if (!serdes_pinctrl)
return -ENOMEM;
serdes_pinctrl->dev = dev;
serdes_pinctrl->parent = serdes;
serdes->pinctrl = serdes_pinctrl;
platform_set_drvdata(pdev, serdes_pinctrl);
serdes_pinctrl->regmap = dev_get_regmap(dev->parent, NULL);
if (!serdes_pinctrl->regmap)
return dev_err_probe(dev, -ENODEV, "failed to get serdes regmap\n");
pinctrl_desc = devm_kzalloc(dev, sizeof(*pinctrl_desc), GFP_KERNEL);
if (!pinctrl_desc)
return -ENOMEM;
pinctrl_desc->name = dev_name(dev);
pinctrl_desc->owner = THIS_MODULE;
pinctrl_desc->pctlops = &serdes_pinctrl_ops;
pinctrl_desc->pmxops = &serdes_pinmux_ops;
pinctrl_desc->confops = &serdes_pinconf_ops;
pinctrl_desc->npins = pinctrl_info->num_pins;
serdes_pinctrl->pdesc = devm_kcalloc(dev,
pinctrl_info->num_pins,
sizeof(*serdes_pinctrl->pdesc),
GFP_KERNEL);
pinctrl_desc->pins = serdes_pinctrl->pdesc;
if (!serdes_pinctrl->pdesc)
return -ENOMEM;
serdes_pinctrl->pinctrl_desc = pinctrl_desc;
for_each_available_child_of_node(dev->of_node, child) {
ret = of_parse_phandle_with_fixed_args(child, list_name, 3, 0, &of_args);
if (ret) {
dev_err(dev, "Unable to parse %s list property in %s node\n",
list_name, child->name);
} else {
pin_base = of_args.args[1];
SERDES_DBG_MFD("%s:gpio-range=<%d %d>\n", __func__, pin_base,
pin_base + of_args.args[2]);
}
}
if (pin_base) {
for (i = 0; i < pinctrl_info->num_pins; i++) {
serdes_pinctrl->pdesc[i].number = pinctrl_info->pins[i].number + pin_base;
serdes_pinctrl->pdesc[i].name = kasprintf(GFP_KERNEL, "%s-gpio%d",
pinctrl_info->pins[i].name,
serdes_pinctrl->pdesc[i].number);
SERDES_DBG_MFD("%s:pdesc number=%d, name=%s\n", __func__,
serdes_pinctrl->pdesc[i].number,
serdes_pinctrl->pdesc[i].name);
}
} else {
dev_info(serdes->dev, "no pinctrl setting\n");
return 0;
}
serdes_pinctrl->pin_base = pin_base;
/* Add pinctrl */
ret = devm_pinctrl_register_and_init(dev, pinctrl_desc, serdes_pinctrl,
&serdes_pinctrl->pctl);
if (ret)
return dev_err_probe(dev, ret, "failed to register serdes pinctrl\n");
for (i = 0; i < pinctrl_info->num_groups; i++) {
struct group_desc *group = &pinctrl_info->groups[i];
int *grp_pins = devm_kcalloc(dev,
group->num_pins, sizeof(*group->pins), GFP_KERNEL);
for (j = 0; j < group->num_pins; j++) {
grp_pins[j] = pinctrl_info->groups[i].pins[j] + pin_base;
SERDES_DBG_MFD("%s group name %s pin %d base=%d\n", __func__,
pinctrl_info->groups[i].name, grp_pins[j], pin_base);
}
ret = pinctrl_generic_add_group(serdes_pinctrl->pctl, group->name,
grp_pins, group->num_pins, group->data);
if (ret < 0) {
dev_err(dev, "Failed to register serdes group %s\n",
group->name);
return ret;
}
}
for (i = 0; i < pinctrl_info->num_functions; i++) {
const struct function_desc *func = &pinctrl_info->functions[i];
ret = pinmux_generic_add_function(serdes_pinctrl->pctl, func->name,
func->group_names, func->num_group_names,
func->data);
if (ret < 0) {
dev_err(dev, "Failed to register serdes function %s\n",
func->name);
return ret;
}
}
ret = pinctrl_enable(serdes_pinctrl->pctl);
ret = serdes_pinctrl_gpio_init(serdes);
/* pinctrl state*/
serdes->pinctrl_node = devm_pinctrl_get(dev);
if (!IS_ERR(serdes->pinctrl_node)) {
serdes->pins_default =
pinctrl_lookup_state(serdes->pinctrl_node, PINCTRL_STATE_DEFAULT);
serdes->pins_sleep =
pinctrl_lookup_state(serdes->pinctrl_node, PINCTRL_STATE_SLEEP);
}
dev_info(dev, "%s %s serdes_pinctrl_probe successful, pin_base=%d\n",
dev_name(dev->parent), serdes->chip_data->name, pin_base);
return ret;
}
static const struct of_device_id serdes_pinctrl_of_match[] = {
{ .compatible = "rohm,bu18tl82-pinctrl" },
{ .compatible = "rohm,bu18rl82-pinctrl" },
{ .compatible = "maxim,max96745-pinctrl" },
{ .compatible = "maxim,max96752-pinctrl" },
{ .compatible = "maxim,max96755-pinctrl" },
{ .compatible = "maxim,max96772-pinctrl" },
{ .compatible = "rockchip,rkx111-pinctrl" },
{ .compatible = "rockchip,rkx121-pinctrl" },
{ .compatible = "novo,nca9539-pinctrl" },
{ }
};
static struct platform_driver serdes_pinctrl_driver = {
.driver = {
.name = "serdes-pinctrl",
.of_match_table = of_match_ptr(serdes_pinctrl_of_match),
},
.probe = serdes_pinctrl_probe,
};
static int __init serdes_pinctrl_init(void)
{
return platform_driver_register(&serdes_pinctrl_driver);
}
subsys_initcall_sync(serdes_pinctrl_init);
static void __exit serdes_pinctrl_exit(void)
{
platform_driver_unregister(&serdes_pinctrl_driver);
}
module_exit(serdes_pinctrl_exit);
MODULE_AUTHOR("Luo Wei <lw@rock-chips.com>");
MODULE_DESCRIPTION("display pinctrl interface for different serdes");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:serdes-pinctrl");