mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
31
drivers/mfd/display-serdes/Kconfig
Normal file
31
drivers/mfd/display-serdes/Kconfig
Normal 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
|
||||
|
||||
13
drivers/mfd/display-serdes/Makefile
Normal file
13
drivers/mfd/display-serdes/Makefile
Normal 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
|
||||
353
drivers/mfd/display-serdes/core.h
Normal file
353
drivers/mfd/display-serdes/core.h
Normal 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
|
||||
248
drivers/mfd/display-serdes/gpio.h
Normal file
248
drivers/mfd/display-serdes/gpio.h
Normal 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
|
||||
44
drivers/mfd/display-serdes/maxim/Kconfig
Normal file
44
drivers/mfd/display-serdes/maxim/Kconfig
Normal 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
|
||||
9
drivers/mfd/display-serdes/maxim/Makefile
Normal file
9
drivers/mfd/display-serdes/maxim/Makefile
Normal 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
|
||||
781
drivers/mfd/display-serdes/maxim/maxim-max96745.c
Normal file
781
drivers/mfd/display-serdes/maxim/maxim-max96745.c
Normal 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");
|
||||
139
drivers/mfd/display-serdes/maxim/maxim-max96745.h
Normal file
139
drivers/mfd/display-serdes/maxim/maxim-max96745.h
Normal 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
|
||||
319
drivers/mfd/display-serdes/maxim/maxim-max96752.c
Normal file
319
drivers/mfd/display-serdes/maxim/maxim-max96752.c
Normal 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");
|
||||
14
drivers/mfd/display-serdes/maxim/maxim-max96752.h
Normal file
14
drivers/mfd/display-serdes/maxim/maxim-max96752.h
Normal 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
|
||||
719
drivers/mfd/display-serdes/maxim/maxim-max96755.c
Normal file
719
drivers/mfd/display-serdes/maxim/maxim-max96755.c
Normal 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");
|
||||
189
drivers/mfd/display-serdes/maxim/maxim-max96755.h
Normal file
189
drivers/mfd/display-serdes/maxim/maxim-max96755.h
Normal 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
|
||||
328
drivers/mfd/display-serdes/maxim/maxim-max96772.c
Normal file
328
drivers/mfd/display-serdes/maxim/maxim-max96772.c
Normal 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");
|
||||
14
drivers/mfd/display-serdes/maxim/maxim-max96772.h
Normal file
14
drivers/mfd/display-serdes/maxim/maxim-max96772.h
Normal 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
|
||||
352
drivers/mfd/display-serdes/maxim/maxim-max96789.c
Normal file
352
drivers/mfd/display-serdes/maxim/maxim-max96789.c
Normal 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");
|
||||
14
drivers/mfd/display-serdes/maxim/maxim-max96789.h
Normal file
14
drivers/mfd/display-serdes/maxim/maxim-max96789.h
Normal 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
|
||||
20
drivers/mfd/display-serdes/novo/Kconfig
Normal file
20
drivers/mfd/display-serdes/novo/Kconfig
Normal 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
|
||||
6
drivers/mfd/display-serdes/novo/Makefile
Normal file
6
drivers/mfd/display-serdes/novo/Makefile
Normal 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
|
||||
370
drivers/mfd/display-serdes/novo/novo-nca9539.c
Normal file
370
drivers/mfd/display-serdes/novo/novo-nca9539.c
Normal 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");
|
||||
25
drivers/mfd/display-serdes/rockchip/Kconfig
Normal file
25
drivers/mfd/display-serdes/rockchip/Kconfig
Normal 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
|
||||
6
drivers/mfd/display-serdes/rockchip/Makefile
Normal file
6
drivers/mfd/display-serdes/rockchip/Makefile
Normal 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
|
||||
189
drivers/mfd/display-serdes/rockchip/rockchip-rkx111.c
Normal file
189
drivers/mfd/display-serdes/rockchip/rockchip-rkx111.c
Normal 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");
|
||||
189
drivers/mfd/display-serdes/rockchip/rockchip-rkx121.c
Normal file
189
drivers/mfd/display-serdes/rockchip/rockchip-rkx121.c
Normal 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");
|
||||
25
drivers/mfd/display-serdes/rohm/Kconfig
Normal file
25
drivers/mfd/display-serdes/rohm/Kconfig
Normal 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
|
||||
6
drivers/mfd/display-serdes/rohm/Makefile
Normal file
6
drivers/mfd/display-serdes/rohm/Makefile
Normal 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
|
||||
460
drivers/mfd/display-serdes/rohm/rohm-bu18rl82.c
Normal file
460
drivers/mfd/display-serdes/rohm/rohm-bu18rl82.c
Normal 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");
|
||||
376
drivers/mfd/display-serdes/rohm/rohm-bu18rl82.h
Normal file
376
drivers/mfd/display-serdes/rohm/rohm-bu18rl82.h
Normal 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] 1’b1
|
||||
#define BU18RL82_BLOCK_EN_LVDSTX0 0x0011 //h [1] 1’b0
|
||||
#define BU18RL82_BLOCK_EN_VPLL0 0x0011 //h [3] 1’b0
|
||||
#define BU18RL82_BLOCK_EN_SSCG0 0x0011 //h [4] 1’b0
|
||||
#define BU18RL82_BLOCK_EN_CLLRX1 0x0012 //h [0] 1’b1
|
||||
#define BU18RL82_BLOCK_EN_LVDSTX1 0x0012 //h [1] 1’b0
|
||||
#define BU18RL82_BLOCK_EN_VPLL1 0x0012 //h [3] 1’b0
|
||||
#define BU18RL82_BLOCK_EN_SSCG1 0x0012 //h [4] 1’b0
|
||||
#define BU18RL82_BLOCK_EN_CLLTX 0x0013 //h [0] 1’b0
|
||||
#define BU18RL82_BLOCK_EN_FSAFETY 0x0013 //h [1] 1’b0
|
||||
|
||||
#define BU18RL82_IO_SW_GPIO0 0x0057 //h [2:1] 2’b00
|
||||
#define BU18RL82_IO_OEN_GPIO0 0x0057 //h [3] 1’b1
|
||||
#define BU18RL82_IO_PDEN_GPIO0 0x0057 //h [4] 1’b1
|
||||
#define BU18RL82_IO_SW_GPIO1 0x005A //h [2:1] 2’b00
|
||||
#define BU18RL82_IO_OEN_GPIO1 0x005A //h [3] 1’b1
|
||||
#define BU18RL82_IO_PDEN_GPIO1 0x005A //h [4] 1’b1
|
||||
#define BU18RL82_IO_SW_GPIO2 0x005D //h [2:1] 2’b00
|
||||
#define BU18RL82_IO_OEN_GPIO2 0x005D //h [3] 1’b1
|
||||
#define BU18RL82_IO_PDEN_GPIO2 0x005D //h [4] 1’b1
|
||||
#define BU18RL82_IO_SW_GPIO3 0x0060 //h [2:1] 2’b00
|
||||
#define BU18RL82_IO_OEN_GPIO3 0x0060 //h [3] 1’b1
|
||||
#define BU18RL82_IO_PDEN_GPIO3 0x0060 //h [4] 1’b1
|
||||
#define BU18RL82_IO_SW_GPIO4 0x0063 //h [2:1] 2’b00
|
||||
#define BU18RL82_IO_OEN_GPIO4 0x0063 //h [3] 1’b1
|
||||
#define BU18RL82_IO_PDEN_GPIO4 0x0063 //h [4] 1’b1
|
||||
#define BU18RL82_IO_SW_GPIO5 0x0066 //h [2:1] 2’b00
|
||||
#define BU18RL82_IO_OEN_GPIO5 0x0066 //h [2:1] 2’b00
|
||||
#define BU18RL82_IO_PDEN_GPIO5 0x0066 //h [3] 1’b1
|
||||
#define BU18RL82_IO_SW_GPIO6 0x0069 //h [2:1] 2’b00
|
||||
#define BU18RL82_IO_OEN_GPIO6 0x0069 //h [3] 1’b1
|
||||
#define BU18RL82_IO_PDEN_GPIO6 0x0069 //h [4] 1’b1
|
||||
#define BU18RL82_IO_SW_GPIO7 0x006C //h [2:1] 2’b00
|
||||
#define BU18RL82_IO_OEN_GPIO7 0x006C //h [3] 1’b1
|
||||
#define BU18RL82_IO_PDEN_GPIO7 0x006C //h [4] 1’b1
|
||||
|
||||
/*
|
||||
* 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]} 11’h002
|
||||
#define BU18RL82_GPIO_SEL1_HIGH 0x005C //h [2:0],
|
||||
#define BU18RL82_GPIO_SEL1_LOW 0x005B //h [7:0]} 11’h003
|
||||
#define BU18RL82_GPIO_SEL2_HIGH 0x005F //h [2:0],
|
||||
#define BU18RL82_GPIO_SEL2_LOW 0x005E //h [7:0]} 11’h012
|
||||
#define BU18RL82_GPIO_SEL3_HIGH 0x0062 //h [2:0],
|
||||
#define BU18RL82_GPIO_SEL3_LOW 0x0061 //h [7:0]} 11’h013
|
||||
#define BU18RL82_GPIO_SEL4_HIGH 0x0065 //h [2:0],
|
||||
#define BU18RL82_GPIO_SEL4_LOW 0x0064 //h [7:0]} 11’h006
|
||||
#define BU18RL82_GPIO_SEL5_HIGH 0x0068 //h [2:0],
|
||||
#define BU18RL82_GPIO_SEL5_LOW 0x0067 //h [7:0]} 11’h007
|
||||
#define BU18RL82_GPIO_SEL6_HIGH 0x006B //h [2:0],
|
||||
#define BU18RL82_GPIO_SEL6_LOW 0x006A //h [7:0]} 11’h008
|
||||
#define BU18RL82_GPIO_SEL7_HIGH 0x006E //h [2:0],
|
||||
#define BU18RL82_GPIO_SEL7_LOW 0x006D //h [7:0]} 11’h009
|
||||
|
||||
/*gpio register for define bu18rl82 gpio pin, and gpio0 to gpio0 default*/
|
||||
#define BU18RL82_BCCTX0__SEL_GPI0 0x042B //h [5:0] 6’h02
|
||||
#define BU18RL82_BCCTX0__SEL_GPI1 0x042C //h [5:0] 6’h03
|
||||
#define BU18RL82_BCCTX0__SEL_GPI2 0x042D //h [5:0] 6’h04
|
||||
#define BU18RL82_BCCTX0__SEL_GPI3 0x042E //h [5:0] 6’h05
|
||||
#define BU18RL82_BCCTX0__SEL_GPI4 0x042F //h [5:0] 6’h06
|
||||
#define BU18RL82_BCCTX0__SEL_GPI5 0x0430 //h [5:0] 6’h07
|
||||
#define BU18RL82_BCCTX0__SEL_GPI6 0x0431 //h [5:0] 6’h08
|
||||
#define BU18RL82_BCCTX0__SEL_GPI7 0x0432 //h [5:0] 6’h09
|
||||
#define BU18RL82_BCCTX1__SEL_GPI0 0x052B //h [5:0] 6’h02
|
||||
#define BU18RL82_BCCTX1__SEL_GPI1 0x052C //h [5:0] 6’h03
|
||||
#define BU18RL82_BCCTX1__SEL_GPI2 0x052D //h [5:0] 6’h04
|
||||
#define BU18RL82_BCCTX1__SEL_GPI3 0x052E //h [5:0] 6’h05
|
||||
#define BU18RL82_BCCTX1__SEL_GPI4 0x052F //h [5:0] 6’h06
|
||||
#define BU18RL82_BCCTX1__SEL_GPI5 0x0530 //h [5:0] 6’h07
|
||||
#define BU18RL82_BCCTX1__SEL_GPI6 0x0531 //h [5:0] 6’h08
|
||||
#define BU18RL82_BCCTX1__SEL_GPI7 0x0532 //h [5:0] 6’h09
|
||||
|
||||
#define BU18RL82_IEN_CLLRX0_LINK_UNLOCK 0x0109 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX0_BIT_ERR 0x0109 //h [3] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX0_ERR_CNT_OVF 0x0109 //h [4] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX1_LINK_UNLOCK 0x010B //h [1] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX1_BIT_ERR 0x010B //h [3] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX1_ERR_CNT_OVF 0x010B //h [4] 1’b0
|
||||
#define BU18RL82_IEN_FCCRX0_CRCERR 0x010D //h [0] 1’b0
|
||||
#define BU18RL82_IEN_FCCRX1_CRCERR 0x010E //h [0] 1’b0
|
||||
#define BU18RL82_IEN_BCCDES0_ERR_CRC 0x010F //h [3] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX0_CRCERR_R 0x0110 //h [0] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX0_CRCERR_G 0x0110 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX0_CRCERR_B 0x0110 //h [2] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX1_CRCERR_R 0x0111 //h [0] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX1_CRCERR_G 0x0111 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_CLLRX1_CRCERR_B 0x0111 //h [2] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_STATUS0 0x0112 //h [0] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_STATUS1 0x0112 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_STATUS2 0x0112 //h [2] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_STATUS3 0x0112 //h [3] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_ERR_REGION0 0x0113 //h [0] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_ERR_REGION1 0x0113 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_ERR_REGION2 0x0113 //h [2] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_ERR_REGION3 0x0113 //h [3] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_ERR_REGION4 0x0113 //h [4] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_ERR_REGION5 0x0113 //h [5] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_ERR_REGION6 0x0113 //h [6] 1’b0
|
||||
#define BU18RL82_IEN_FS_IMG_ERR_REGION7 0x0113 //h [7] 1’b0
|
||||
#define BU18RL82_IEN_IO_STUCK_GPIO0 0x0114 //h [0] 1’b0
|
||||
#define BU18RL82_IEN_IO_STUCK_GPIO1 0x0114 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_IO_STUCK_GPIO2 0x0114 //h [2] 1’b0
|
||||
#define BU18RL82_IEN_IO_STUCK_GPIO3 0x0114 //h [3] 1’b0
|
||||
#define BU18RL82_IEN_IO_STUCK_GPIO4 0x0114 //h [4] 1’b0
|
||||
#define BU18RL82_IEN_IO_STUCK_GPIO5 0x0114 //h [5] 1’b0
|
||||
#define BU18RL82_IEN_IO_STUCK_GPIO6 0x0114 //h [6] 1’b0
|
||||
#define BU18RL82_IEN_IO_STUCK_GPIO7 0x0114 //h [7] 1’b0
|
||||
#define BU18RL82_IEN_IO_STUCK_IRQ 0x0115 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_IDS_UNSTABLE 0x0115 //h [7] 1’b0
|
||||
#define BU18RL82_IEN_I2C_A_TIMEOUT 0x0116 //h [0] 1’b0
|
||||
#define BU18RL82_IEN_I2C_A_XMIT_ERR 0x0116 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_REGCRC_ERR_PAGE0 0x0117 //h [0] 1’b0
|
||||
#define BU18RL82_IEN_REGCRC_ERR_PAGE1 0x0117 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_REGCRC_ERR_PAGE2 0x0117 //h [2] 1’b0
|
||||
#define BU18RL82_IEN_REGCRC_ERR_PAGE3 0x0117 //h [3] 1’b0
|
||||
#define BU18RL82_IEN_REGCRC_ERR_PAGE4 0x0117 //h [4] 1’b0
|
||||
#define BU18RL82_IEN_REGCRC_ERR_PAGE5 0x0117 //h [5] 1’b0
|
||||
#define BU18RL82_IEN_REGCRC_ERR_PAGE6 0x0117 //h [6] 1’b0
|
||||
#define BU18RL82_IEN_REGCRC_ERR_PAGE7 0x0117 //h [7] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_CLKIN_STOP 0x0118 //h [0] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_CLKIN_UNLOCK 0x0118 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_OSC_STOP 0x0118 //h [4] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_OSC_UNLOCK 0x0118 //h [5] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_CLLRX0_PCLK_STOP 0x0119 //h [0] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_CLLRX0_PCLK_UNLOCK 0x0119 //h [1] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_LVDSTX0_CLK_STOP 0x0119 //h [4] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_LVDSTX0_CLK_UNLOCK 0x0119 //h [5] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_CLLRX1_PCLK_STOP 0x011A //h [0] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_CLLRX1_PCLK_UNLOCK 0x011A //h [1] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_LVDSTX1_CLK_STOP 0x011A //h [4] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_LVDSTX1_CLK_UNLOCK 0x011A //h [5] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_CLLTX0_SCLK_STOP 0x011B //h [0] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x011B //h [1] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_CLLTX0_PLLREF_STOP 0x011B //h [4] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x011B //h [5] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_LVDSTX0_PLLREF_STOP 0x011C //h [0] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_LVDSTX0_PLLREF_UNLOCK0x011C //h [1] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_LVDSTX1_PLLREF_STOP 0x011C //h [4] 1’b0
|
||||
#define BU18RL82_IEN_CLKDETECT_LVDSTX1_PLLREF_UNLOCK 0x011C //h [5] 1’b0
|
||||
|
||||
#define BU18RL82_ISR_CLEAR_ALL 0x0105 //h [0] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX0_LINK_UNLOCK 0x0129 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX0_BIT_ERR 0x0129 //h [3] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX0_ERR_CNT_OVF 0x0129 //h [4] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX1_ERR_CNT_OVF 0x012B //h [4] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX1_LINK_UNLOCK 0x012B //h [1] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX1_BIT_ERR 0x012B //h [3] 1’b0
|
||||
#define BU18RL82_ISR_FCCRX0_CRCERR 0x012D //h [0] 1’b0
|
||||
#define BU18RL82_ISR_FCCRX1_CRCERR 0x012E //h [0] 1’b0
|
||||
#define BU18RL82_ISR_BCCDES0_ERR_CRC 0x012F //h [3] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX0_CRCERR_R 0x0130 //h [0] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX0_CRCERR_G 0x0130 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX0_CRCERR_B 0x0130 //h [2] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX1_CRCERR_R 0x0131 //h [0] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX1_CRCERR_G 0x0131 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_CLLRX1_CRCERR_B 0x0131 //h [2] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_STATUS0 0x0132 //h [0] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_STATUS1 0x0132 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_STATUS2 0x0132 //h [2] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_STATUS3 0x0132 //h [3] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_ERR_REGION0 0x0133 //h [0] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_ERR_REGION1 0x0133 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_ERR_REGION2 0x0133 //h [2] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_ERR_REGION3 0x0133 //h [3] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_ERR_REGION4 0x0133 //h [4] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_ERR_REGION5 0x0133 //h [5] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_ERR_REGION6 0x0133 //h [6] 1’b0
|
||||
#define BU18RL82_ISR_FS_IMG_ERR_REGION7 0x0133 //h [7] 1’b0
|
||||
#define BU18RL82_ISR_IO_STUCK_GPIO0 0x0134 //h [0] 1’b0
|
||||
#define BU18RL82_ISR_IO_STUCK_GPIO1 0x0134 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_IO_STUCK_GPIO2 0x0134 //h [2] 1’b0
|
||||
#define BU18RL82_ISR_IO_STUCK_GPIO3 0x0134 //h [3] 1’b0
|
||||
#define BU18RL82_ISR_IO_STUCK_GPIO4 0x0134 //h [4] 1’b0
|
||||
#define BU18RL82_ISR_IO_STUCK_GPIO5 0x0134 //h [5] 1’b0
|
||||
#define BU18RL82_ISR_IO_STUCK_GPIO6 0x0134 //h [6] 1’b0
|
||||
#define BU18RL82_ISR_IO_STUCK_GPIO7 0x0134 //h [7] 1’b0
|
||||
#define BU18RL82_ISR_IO_STUCK_IRQ 0x0135 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_IDS_UNSTABLE 0x0135 //h [7] 1’b0
|
||||
#define BU18RL82_ISR_I2C_A_TIMEOUT 0x0136 //h [0] 1’b0
|
||||
#define BU18RL82_ISR_I2C_A_XMIT_ERR 0x0136 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_REGCRC_ERR_PAGE0 0x0137 //h [0] 1’b0
|
||||
#define BU18RL82_ISR_REGCRC_ERR_PAGE1 0x0137 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_REGCRC_ERR_PAGE2 0x0137 //h [2] 1’b0
|
||||
#define BU18RL82_ISR_REGCRC_ERR_PAGE3 0x0137 //h [3] 1’b0
|
||||
#define BU18RL82_ISR_REGCRC_ERR_PAGE4 0x0137 //h [4] 1’b0
|
||||
#define BU18RL82_ISR_REGCRC_ERR_PAGE5 0x0137 //h [5] 1’b0
|
||||
#define BU18RL82_ISR_REGCRC_ERR_PAGE6 0x0137 //h [6] 1’b0
|
||||
#define BU18RL82_ISR_REGCRC_ERR_PAGE7 0x0137 //h [7] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_CLKIN_STOP 0x0138 //h [0] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_CLKIN_UNLOCK 0x0138 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_OSC_STOP 0x0138 //h [4] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_OSC_UNLOCK 0x0138 //h [5] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_CLLRX0_PCLK_STOP 0x0139 //h [0] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_CLLRX0_PCLK_UNLOCK 0x0139 //h [1] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_LVDSTX0_CLK_STOP 0x0139 //h [4] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_LVDSTX0_CLK_UNLOCK 0x0139 //h [5] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_CLLRX1_PCLK_STOP 0x013A //h [0] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_CLLRX1_PCLK_UNLOCK 0x013A //h [1] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_LVDSTX1_CLK_STOP 0x013A //h [4] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_LVDSTX1_CLK_UNLOCK 0x013A //h [5] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_CLLTX0_SCLK_STOP 0x013B //h [0] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x013B //h [1] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_CLLTX0_PLLREF_STOP 0x013B //h [4] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x013B //h [5] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_LVDSTX0_PLLREF_STOP 0x013C //h [0] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_LVDSTX0_PLLREF_UNLOCK0x013C //h [1] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_LVDSTX1_PLLREF_STOP 0x013C //h [4] 1’b0
|
||||
#define BU18RL82_ISR_CLKDETECT_LVDSTX1_PLLREF_UNLOCK 0x013C //h [5] 1’b0
|
||||
|
||||
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
|
||||
461
drivers/mfd/display-serdes/rohm/rohm-bu18tl82.c
Normal file
461
drivers/mfd/display-serdes/rohm/rohm-bu18tl82.c
Normal 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");
|
||||
438
drivers/mfd/display-serdes/rohm/rohm-bu18tl82.h
Normal file
438
drivers/mfd/display-serdes/rohm/rohm-bu18tl82.h
Normal 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] 1’b0
|
||||
#define BU18TL82_BLOCK_EN_LVDSRX0 0x0013 //h [1] 1’b0
|
||||
#define BU18TL82_BLOCK_EN_CLLTX0 0x0013 //h [3] 1’b0
|
||||
#define BU18TL82_BLOCK_EN_VPLL0 0x0013 //h [4] 1’b0
|
||||
#define BU18TL82_BLOCK_EN_SSCG0 0x0013 //h [5] 1’b0
|
||||
#define BU18TL82_BLOCK_EN_MIPIRX1 0x0014 //h [0] 1’b0
|
||||
#define BU18TL82_BLOCK_EN_LVDSRX1 0x0014 //h [1] 1’b0
|
||||
#define BU18TL82_BLOCK_EN_CLLTX1 0x0014 //h [3] 1’b0
|
||||
#define BU18TL82_BLOCK_EN_VPLL1 0x0014 //h [4] 1’b0
|
||||
#define BU18TL82_BLOCK_EN_SSCG1 0x0014 //h [5] 1’b0
|
||||
|
||||
/*gpio register for driver/direction/pull-down*/
|
||||
#define BU18TL82_IO_SW_GPIO0 0x002A //h [2:1] 2’b00
|
||||
#define BU18TL82_IO_OEN_GPIO0 0x002A //h [3] 1’b1
|
||||
#define BU18TL82_IO_PDEN_GPIO0 0x002A //h [4] 1’b1
|
||||
#define BU18TL82_IO_SW_GPIO1 0x002D //h [2:1] 2’b00
|
||||
#define BU18TL82_IO_OEN_GPIO1 0x002D //h [3] 1’b1
|
||||
#define BU18TL82_IO_PDEN_GPIO1 0x002D //h [4] 1’b1
|
||||
#define BU18TL82_IO_SW_GPIO2 0x0030 //h [2:1] 2’b00
|
||||
#define BU18TL82_IO_OEN_GPIO2 0x0030 //h [3] 1’b1
|
||||
#define BU18TL82_IO_PDEN_GPIO2 0x0030 //h [4] 1’b1
|
||||
#define BU18TL82_IO_SW_GPIO3 0x0033 //h [2:1] 2’b00
|
||||
#define BU18TL82_IO_OEN_GPIO3 0x0033 //h [3] 1’b1
|
||||
#define BU18TL82_IO_PDEN_GPIO3 0x0033 //h [4] 1’b1
|
||||
#define BU18TL82_IO_SW_GPIO4 0x0036 //h [2:1] 2’b00
|
||||
#define BU18TL82_IO_OEN_GPIO4 0x0036 //h [3] 1’b1
|
||||
#define BU18TL82_IO_PDEN_GPIO4 0x0036 //h [4] 1’b1
|
||||
#define BU18TL82_IO_SW_GPIO5 0x0039 //h [2:1] 2’b00
|
||||
#define BU18TL82_IO_OEN_GPIO5 0x0039 //h [3] 1’b1
|
||||
#define BU18TL82_IO_PDEN_GPIO5 0x0039 //h [4] 1’b1
|
||||
#define BU18TL82_IO_SW_GPIO6 0x003C //h [2:1] 2’b00
|
||||
#define BU18TL82_IO_OEN_GPIO6 0x003C //h [3] 1’b1
|
||||
#define BU18TL82_IO_PDEN_GPIO6 0x003C //h [4] 1’b1
|
||||
#define BU18TL82_IO_SW_GPIO7 0x003F //h [2:1] 2’b00
|
||||
#define BU18TL82_IO_OEN_GPIO7 0x003F //h [3] 1’b1
|
||||
#define BU18TL82_IO_PDEN_GPIO7 0x003F //h [4] 1’b1
|
||||
|
||||
/*
|
||||
* 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] 11’h002
|
||||
#define BU18TL82_GPIO_SEL1_HIGH 0x002F //h [2:0],
|
||||
#define BU18TL82_GPIO_SEL1_LOW 0x002E //h [7:0] 11’h003
|
||||
#define BU18TL82_GPIO_SEL2_HIGH 0x0032 //h [2:0],
|
||||
#define BU18TL82_GPIO_SEL2_LOW 0x0031 //h [7:0] 11’h004
|
||||
#define BU18TL82_GPIO_SEL3_HIGH 0x0035 //h [2:0],
|
||||
#define BU18TL82_GPIO_SEL3_LOW 0x0034 //h [7:0] 11’h005
|
||||
#define BU18TL82_GPIO_SEL4_HIGH 0x0038 //h [2:0],
|
||||
#define BU18TL82_GPIO_SEL4_LOW 0x0037 //h [7:0] 11’h006
|
||||
#define BU18TL82_GPIO_SEL5_HIGH 0x003B //h [2:0],
|
||||
#define BU18TL82_GPIO_SEL5_LOW 0x003A //h [7:0] 11’h007
|
||||
/*datasheet about gpio6/7 need modify*/
|
||||
#define BU18TL82_GPIO_SEL6_LOW 0x003E //h [2:0],
|
||||
#define BU18TL82_GPIO_SEL6_HIGH 0x003D //h [7:0] 11’h008
|
||||
#define BU18TL82_GPIO_SEL7_LOW 0x0041 //h [2:0],
|
||||
#define BU18TL82_GPIO_SEL7_HIGH 0x0040 //h [7:0] 11’h009
|
||||
|
||||
/*gpio register for define bu18tl82 gpio pin, and gpio0 to gpio0 default*/
|
||||
#define BU18TL82_FCCTX0_SEL_GPI0 0x02A7 //h [4:0] 5’h02
|
||||
#define BU18TL82_FCCTX0_SEL_GPI1 0x02A8 //h [4:0] 5’h03
|
||||
#define BU18TL82_FCCTX0_SEL_GPI2 0x02A9 //h [4:0] 5’h04
|
||||
#define BU18TL82_FCCTX0_SEL_GPI3 0x02AA //h [4:0] 5’h05
|
||||
#define BU18TL82_FCCTX0_SEL_GPI4 0x02AB //h [4:0] 5’h06
|
||||
#define BU18TL82_FCCTX0_SEL_GPI5 0x02AC //h [4:0] 5’h07
|
||||
#define BU18TL82_FCCTX0_SEL_GPI6 0x02AD //h [4:0] 5’h08
|
||||
#define BU18TL82_FCCTX0_SEL_GPI7 0x02AE //h [4:0] 5’h09
|
||||
#define BU18TL82_CLLTX0_SEL_GPI0 0x02AF //h [4:0] 5’h04
|
||||
#define BU18TL82_CLLTX0_SEL_GPI1 0x02B0 //h [4:0] 5’h05
|
||||
|
||||
#define BU18TL82_FCCTX1_SEL_GPI0 0x03A7 //h [4:0] 5’h02
|
||||
#define BU18TL82_FCCTX1_SEL_GPI1 0x03A8 //h [4:0] 5’h03
|
||||
#define BU18TL82_FCCTX1_SEL_GPI2 0x03A9 //h [4:0] 5’h04
|
||||
#define BU18TL82_FCCTX1_SEL_GPI3 0x03AA //h [4:0] 5’h05
|
||||
#define BU18TL82_FCCTX1_SEL_GPI4 0x03AB //h [4:0] 5’h06
|
||||
#define BU18TL82_FCCTX1_SEL_GPI5 0x03AC //h [4:0] 5’h07
|
||||
#define BU18TL82_FCCTX1_SEL_GPI6 0x03AD //h [4:0] 5’h08
|
||||
#define BU18TL82_FCCTX1_SEL_GPI7 0x03AE //h [4:0] 5’h09
|
||||
#define BU18TL82_CLLTX1_SEL_GPI0 0x03AF //h [4:0] 5’h04
|
||||
#define BU18TL82_CLLTX1_SEL_GPI1 0x03B0 //h [4:0] 5’h05
|
||||
|
||||
/*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] 1’b0
|
||||
#define BU18TL82_ISR_BCCRX0_STATUS_NEAR_LOST 0x0131 //h[7]
|
||||
#define BU18TL82_ISR_BCCDES1_ERR_CRC 0x0132 //h [3] 1’b0
|
||||
#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] 1’b0
|
||||
#define BU18TL82_ISR_I2C_A_TIMEOUT 0x013b //h [0] 1’b0
|
||||
#define BU18TL82_ISR_I2C_A_XMIT_ERR 0x013b //h [1] 1’b0
|
||||
#define BU18TL82_ISR_I2C_B_TIMEOUT 0x013c //h [0] 1’b0
|
||||
#define BU18TL82_ISR_I2C_B_XMIT_ERR 0x013c //h [1] 1’b0
|
||||
#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] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLKIN0_UNLOCK 0x013e //h [1] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_OSC_STOP 0x013e //h [4] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_OSC_UNLOCK 0x013e //h [5] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLKIN1_STOP 0x013f //h [0] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLKIN1_UNLOCK 0x013f //h [1] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_LVDSRX0_STOP 0x0140 //h [0] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_LVDSRX0_UNLOCK 0x0140 //h [1] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_MIPIRX0_STOP 0x0140 //h [4] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_MIPIRX0_UNLOCK 0x0140 //h [5] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_LVDSRX1_STOP 0x0141 //h [0] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_LVDSRX1_UNLOCK 0x0141 //h [1] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_MIPIRX1_STOP 0x0141 //h [4] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_MIPIRX1_UNLOCK 0x0141 //h [5] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLLTX0_SCLK_STOP 0x0142 //h [0] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x0142 //h [1] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLLTX0_PLLREF_STOP 0x0142 //h [4] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x0142 //h [5] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLLTX1_SCLK_STOP 0x0143 //h [0] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLLTX1_SCLK_UNLOCK 0x0143 //h [1] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLLTX1_PLLREF_STOP 0x0143 //h [4] 1’b0
|
||||
#define BU18TL82_ISR_CLKDETECT_CLLTX1_PLLREF_UNLOCK 0x0143 //h [5] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR00 0x0149 //h [0] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR01 0x0149 //h [1] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR02 0x0149 //h [2] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR03 0x0149 //h [3] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR04 0x0149 //h [4] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR05 0x0149 //h [5] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR06 0x0149 //h [6] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR07 0x0149 //h [7] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR08 0x014a //h [0] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR09 0x014a //h [1] 1’b0
|
||||
#define BU18TL82_ISR_STATUS_RX0_ISR10 0x014a //h [2] 1’b0
|
||||
|
||||
#define BU18TL82_IEN_BCCDES0_ERR_CRC 0x0109 //h [3] 1’b0
|
||||
#define BU18TL82_IEN_BCCRX0_STATUS_NEAR_LOST 0x0109 //h[7]
|
||||
#define BU18TL82_IEN_BCCDES1_ERR_CRC 0x010A //h [3] 1’b0
|
||||
#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] 1’b0
|
||||
#define BU18TL82_IEN_I2C_A_TIMEOUT 0x0113 //h [0] 1’b0
|
||||
#define BU18TL82_IEN_I2C_A_XMIT_ERR 0x0113 //h [1] 1’b0
|
||||
#define BU18TL82_IEN_I2C_B_TIMEOUT 0x0114 //h [0] 1’b0
|
||||
#define BU18TL82_IEN_I2C_B_XMIT_ERR 0x0114 //h [1] 1’b0
|
||||
#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] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLKIN0_UNLOCK 0x0116 //h [1] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_OSC_STOP 0x0116 //h [4] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_OSC_UNLOCK 0x0116 //h [5] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLKIN1_STOP 0x0117 //h [0] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLKIN1_UNLOCK 0x0117 //h [1] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_LVDSRX0_STOP 0x0118 //h [0] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_LVDSRX0_UNLOCK 0x0118 //h [1] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_MIPIRX0_STOP 0x0118 //h [4] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_MIPIRX0_UNLOCK 0x0118 //h [5] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_LVDSRX1_STOP 0x0119 //h [0] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_LVDSRX1_UNLOCK 0x0119 //h [1] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_MIPIRX1_STOP 0x0119 //h [4] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_MIPIRX1_UNLOCK 0x0119 //h [5] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLLTX0_SCLK_STOP 0x011A //h [0] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLLTX0_SCLK_UNLOCK 0x011A //h [1] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLLTX0_PLLREF_STOP 0x011A //h [4] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLLTX0_PLLREF_UNLOCK 0x011A //h [5] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLLTX1_SCLK_STOP 0x011B //h [0] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLLTX1_SCLK_UNLOCK 0x011B //h [1] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLLTX1_PLLREF_STOP 0x011B //h [4] 1’b0
|
||||
#define BU18TL82_IEN_CLKDETECT_CLLTX1_PLLREF_UNLOCK 0x011B //h [5] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR00 0x0121 //h [0] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR01 0x0121 //h [1] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR02 0x0121 //h [2] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR03 0x0121 //h [3] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR04 0x0121 //h [4] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR05 0x0121 //h [5] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR06 0x0121 //h [6] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR07 0x0121 //h [7] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR08 0x0122 //h [0] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR09 0x0122 //h [1] 1’b0
|
||||
#define BU18TL82_IEN_STATUS_RX0_ISR10 0x0122 //h [2] 1’b0
|
||||
|
||||
|
||||
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
|
||||
354
drivers/mfd/display-serdes/serdes-bridge.c
Normal file
354
drivers/mfd/display-serdes/serdes-bridge.c
Normal 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");
|
||||
391
drivers/mfd/display-serdes/serdes-core.c
Normal file
391
drivers/mfd/display-serdes/serdes-core.c
Normal 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");
|
||||
253
drivers/mfd/display-serdes/serdes-gpio.c
Normal file
253
drivers/mfd/display-serdes/serdes-gpio.c
Normal 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");
|
||||
337
drivers/mfd/display-serdes/serdes-i2c.c
Normal file
337
drivers/mfd/display-serdes/serdes-i2c.c
Normal 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");
|
||||
109
drivers/mfd/display-serdes/serdes-irq.c
Normal file
109
drivers/mfd/display-serdes/serdes-irq.c
Normal 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");
|
||||
246
drivers/mfd/display-serdes/serdes-panel.c
Normal file
246
drivers/mfd/display-serdes/serdes-panel.c
Normal 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");
|
||||
393
drivers/mfd/display-serdes/serdes-pinctrl.c
Normal file
393
drivers/mfd/display-serdes/serdes-pinctrl.c
Normal 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");
|
||||
Reference in New Issue
Block a user