mfd: Add support for Maxim MAX96755F
The MAX96755F convert MIPI DSI 4-lane input port data to GMSL2 high-speed serial link protocol. They also send and receive control channel and peripheral control data, enabling bidirectional transmission of video and data over cables in excess of 15 meters in length. Signed-off-by: Guochun Huang <hero.huang@rock-chips.com> Change-Id: I540bd4ca61ae6b6e77cb9635567690fe3367a281
This commit is contained in:
parent
6a4a40a39d
commit
b564d3921a
|
|
@ -939,6 +939,14 @@ config MFD_MAX96752F
|
|||
help
|
||||
Say yes here to add support for Maxim Semiconductor MAX96752F.
|
||||
|
||||
config MFD_MAX96755F
|
||||
tristate "Maxim Semiconductor MAX96755 GMSL2 Serializer Support"
|
||||
depends on I2C
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to add support for Maxim Semiconductor MAX96755.
|
||||
|
||||
config MFD_MT6360
|
||||
tristate "Mediatek MT6360 SubPMIC"
|
||||
select MFD_CORE
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o
|
|||
obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o
|
||||
obj-$(CONFIG_MFD_MAX96745) += max96745.o
|
||||
obj-$(CONFIG_MFD_MAX96752F) += max96752f.o
|
||||
obj-$(CONFIG_MFD_MAX96755F) += max96755f.o
|
||||
|
||||
obj-$(CONFIG_MFD_MP2629) += mp2629.o
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,261 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Maxim max96755f MFD driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co. Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/mfd/max96755f.h>
|
||||
|
||||
struct max96755f {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct regulator *supply;
|
||||
struct gpio_desc *pwdnb_gpio;
|
||||
struct gpio_desc *lock_gpio;
|
||||
bool split_mode;
|
||||
};
|
||||
|
||||
static const struct mfd_cell max96755f_devs[] = {
|
||||
{
|
||||
.name = "max96755f-pinctrl",
|
||||
.of_compatible = "maxim,max96755f-pinctrl",
|
||||
}, {
|
||||
.name = "max96755f-bridge",
|
||||
.of_compatible = "maxim,max96755f-bridge",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config max96755f_regmap_config = {
|
||||
.name = "max96755f",
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x1b17,
|
||||
};
|
||||
|
||||
static int max96755f_select(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct max96755f *max96755f = dev_get_drvdata(muxc->dev);
|
||||
u32 link_cfg, val;
|
||||
int ret;
|
||||
|
||||
regmap_update_bits(max96755f->regmap, 0x0001, DIS_REM_CC,
|
||||
FIELD_PREP(DIS_REM_CC, 0));
|
||||
|
||||
if (!max96755f->split_mode)
|
||||
return 0;
|
||||
|
||||
regmap_read(max96755f->regmap, 0x0010, &link_cfg);
|
||||
if ((link_cfg & LINK_CFG) == SPLITTER_MODE)
|
||||
return 0;
|
||||
|
||||
if (chan == 0 && (link_cfg & LINK_CFG) != LINKA) {
|
||||
regmap_update_bits(max96755f->regmap, 0x0010,
|
||||
RESET_ONESHOT | AUTO_LINK | LINK_CFG,
|
||||
FIELD_PREP(RESET_ONESHOT, 1) |
|
||||
FIELD_PREP(AUTO_LINK, 0) |
|
||||
FIELD_PREP(LINK_CFG, LINKA));
|
||||
} else if (chan == 1 && (link_cfg & LINK_CFG) != LINKB) {
|
||||
regmap_update_bits(max96755f->regmap, 0x0010,
|
||||
RESET_ONESHOT | AUTO_LINK | LINK_CFG,
|
||||
FIELD_PREP(RESET_ONESHOT, 1) |
|
||||
FIELD_PREP(AUTO_LINK, 0) |
|
||||
FIELD_PREP(LINK_CFG, LINKB));
|
||||
}
|
||||
|
||||
ret = regmap_read_poll_timeout(max96755f->regmap, 0x0013, val,
|
||||
val & LOCKED, 100,
|
||||
50 * USEC_PER_MSEC);
|
||||
if (ret < 0) {
|
||||
dev_err(max96755f->dev, "GMSL2 link lock timeout\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max96755f_deselect(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct max96755f *max96755f = dev_get_drvdata(muxc->dev);
|
||||
|
||||
regmap_update_bits(max96755f->regmap, 0x0001, DIS_REM_CC,
|
||||
FIELD_PREP(DIS_REM_CC, 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max96755f_power_off(void *data)
|
||||
{
|
||||
struct max96755f *max96755f = data;
|
||||
|
||||
if (max96755f->reset_gpio)
|
||||
gpiod_direction_output(max96755f->reset_gpio, 1);
|
||||
|
||||
if (max96755f->enable_gpio)
|
||||
gpiod_direction_output(max96755f->enable_gpio, 0);
|
||||
|
||||
if (max96755f->supply)
|
||||
regulator_disable(max96755f->supply);
|
||||
}
|
||||
|
||||
static int max96755f_power_on(struct max96755f *max96755f)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (max96755f->supply) {
|
||||
ret = regulator_enable(max96755f->supply);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (max96755f->enable_gpio) {
|
||||
gpiod_direction_output(max96755f->enable_gpio, 1);
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
if (max96755f->reset_gpio) {
|
||||
gpiod_direction_output(max96755f->reset_gpio, 0);
|
||||
msleep(100);
|
||||
gpiod_direction_output(max96755f->reset_gpio, 1);
|
||||
msleep(100);
|
||||
gpiod_direction_output(max96755f->reset_gpio, 0);
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
regmap_update_bits(max96755f->regmap, 0x0001, DIS_REM_CC,
|
||||
FIELD_PREP(DIS_REM_CC, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max96755f_i2c_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *child;
|
||||
struct max96755f *max96755f;
|
||||
unsigned int nr = 0;
|
||||
int ret;
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, child) {
|
||||
if (!of_find_property(child, "reg", NULL))
|
||||
continue;
|
||||
|
||||
nr++;
|
||||
}
|
||||
|
||||
max96755f = devm_kzalloc(dev, sizeof(*max96755f), GFP_KERNEL);
|
||||
if (!max96755f)
|
||||
return -ENOMEM;
|
||||
|
||||
max96755f->muxc = i2c_mux_alloc(client->adapter, dev, nr, 0,
|
||||
I2C_MUX_LOCKED, max96755f_select,
|
||||
max96755f_deselect);
|
||||
if (!max96755f->muxc)
|
||||
return -ENOMEM;
|
||||
|
||||
if (nr == 2)
|
||||
max96755f->split_mode = true;
|
||||
|
||||
max96755f->dev = dev;
|
||||
i2c_set_clientdata(client, max96755f);
|
||||
|
||||
max96755f->supply = devm_regulator_get(dev, "power");
|
||||
if (IS_ERR(max96755f->supply))
|
||||
return dev_err_probe(dev, PTR_ERR(max96755f->supply),
|
||||
"failed to get power supply\n");
|
||||
|
||||
max96755f->lock_gpio = devm_gpiod_get_optional(dev, "lock", GPIOD_IN);
|
||||
if (IS_ERR(max96755f->lock_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(max96755f->lock_gpio),
|
||||
"failed to get lock GPIO\n");
|
||||
|
||||
max96755f->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_ASIS);
|
||||
if (IS_ERR(max96755f->enable_gpio)) {
|
||||
return dev_err_probe(dev, PTR_ERR(max96755f->enable_gpio),
|
||||
"failed to get enable GPIO\n");
|
||||
}
|
||||
|
||||
max96755f->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
|
||||
if (IS_ERR(max96755f->reset_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(max96755f->reset_gpio),
|
||||
"failed to get reset GPIO\n");
|
||||
|
||||
max96755f->regmap = devm_regmap_init_i2c(client, &max96755f_regmap_config);
|
||||
if (IS_ERR(max96755f->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(max96755f->regmap),
|
||||
"failed to initialize regmap");
|
||||
|
||||
ret = max96755f_power_on(max96755f);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, max96755f_power_off, max96755f);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, max96755f_devs,
|
||||
ARRAY_SIZE(max96755f_devs), NULL, 0, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, child) {
|
||||
if (of_property_read_u32(child, "reg", &nr))
|
||||
continue;
|
||||
|
||||
ret = i2c_mux_add_adapter(max96755f->muxc, 0, nr, 0);
|
||||
if (ret) {
|
||||
i2c_mux_del_adapters(max96755f->muxc);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max96755f_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct max96755f *max96755f = i2c_get_clientdata(client);
|
||||
|
||||
i2c_mux_del_adapters(max96755f->muxc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max96755f_i2c_shutdown(struct i2c_client *client)
|
||||
{
|
||||
struct max96755f *max96755f = i2c_get_clientdata(client);
|
||||
|
||||
max96755f_power_off(max96755f);
|
||||
}
|
||||
|
||||
static const struct of_device_id max96755f_of_match[] = {
|
||||
{ .compatible = "maxim,max96755f", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max96755f_of_match);
|
||||
|
||||
static struct i2c_driver max96755f_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max96755f",
|
||||
.of_match_table = max96755f_of_match,
|
||||
},
|
||||
.probe_new = max96755f_i2c_probe,
|
||||
.remove = max96755f_i2c_remove,
|
||||
.shutdown = max96755f_i2c_shutdown,
|
||||
};
|
||||
|
||||
module_i2c_driver(max96755f_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Guochun Huang<hero.huang@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Maxim max96755f MFD driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Defining registers address and its bit definitions of MAX96752F
|
||||
*
|
||||
* Copyright (c) 2022 Rockchip Electronics Co. Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _MFD_MAX96755F_H_
|
||||
#define _MFD_MAX96755F_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)
|
||||
|
||||
/* 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)
|
||||
|
||||
/* 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)
|
||||
|
||||
enum link_mode {
|
||||
DUAL_LINK,
|
||||
LINKA,
|
||||
LINKB,
|
||||
SPLITTER_MODE,
|
||||
};
|
||||
|
||||
#endif /* _MFD_MAX96755F_H_ */
|
||||
Loading…
Reference in New Issue