diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b6ef2552a7b1..1fb23af078a3 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -921,6 +921,15 @@ config MFD_MAX8998 additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX96745 + tristate "Maxim Semiconductor MAX96745 GMSL2 Serializer Support" + depends on I2C + select MFD_CORE + select REGMAP_I2C + select I2C_MUX + help + Say yes here to add support for Maxim Semiconductor MAX96745. + config MFD_MAX96752F tristate "Maxim Semiconductor MAX96752F GMSL2 Deserializer Support" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 984a1f1ed59c..cbb29fba34e3 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -170,6 +170,7 @@ max8925-objs := max8925-core.o max8925-i2c.o obj-$(CONFIG_MFD_MAX8925) += max8925.o 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_MP2629) += mp2629.o diff --git a/drivers/mfd/max96745.c b/drivers/mfd/max96745.c new file mode 100644 index 000000000000..41a31c18dc2a --- /dev/null +++ b/drivers/mfd/max96745.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Maxim MAX96745 MFD driver + * + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct max96745 { + struct device *dev; + struct regmap *regmap; + struct i2c_mux_core *muxc; + struct gpio_desc *enable_gpio; + struct gpio_desc *lock_gpio; +}; + +static const struct mfd_cell max96745_devs[] = { + { + .name = "max96745-pinctrl", + .of_compatible = "maxim,max96745-pinctrl", + }, { + .name = "max96745-bridge", + .of_compatible = "maxim,max96745-bridge", + }, +}; + +static const struct regmap_config max96745_regmap_config = { + .name = "max96745", + .reg_bits = 16, + .val_bits = 8, + .max_register = 0x8000, +}; + +static int max96745_select(struct i2c_mux_core *muxc, u32 chan) +{ + struct max96745 *max96745 = dev_get_drvdata(muxc->dev); + + if (chan == 0) { + regmap_update_bits(max96745->regmap, 0x0028, LINK_EN, + FIELD_PREP(LINK_EN, 1)); + } else if (chan == 1) { + regmap_update_bits(max96745->regmap, 0x0032, LINK_EN, + FIELD_PREP(LINK_EN, 1)); + } else { + regmap_update_bits(max96745->regmap, 0x0028, LINK_EN, + FIELD_PREP(LINK_EN, 1)); + regmap_update_bits(max96745->regmap, 0x0032, LINK_EN, + FIELD_PREP(LINK_EN, 1)); + } + + return 0; +} + +static void max96745_power_off(void *data) +{ + struct max96745 *max96745 = data; + + if (max96745->enable_gpio) + gpiod_direction_output(max96745->enable_gpio, 0); +} + +static int max96745_power_on(struct max96745 *max96745) +{ + u32 val; + int ret; + + ret = regmap_read(max96745->regmap, 0x0107, &val); + if (!ret && FIELD_GET(VID_TX_ACTIVE_A | VID_TX_ACTIVE_B, val)) + return 0; + + if (max96745->enable_gpio) + gpiod_direction_output(max96745->enable_gpio, 1); + + msleep(100); + + ret = regmap_update_bits(max96745->regmap, 0x0010, RESET_ALL, + FIELD_PREP(RESET_ALL, 1)); + if (ret < 0) + return ret; + + msleep(100); + + return 0; +} + +static int max96745_i2c_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device_node *child; + struct max96745 *max96745; + 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++; + } + + max96745 = devm_kzalloc(dev, sizeof(*max96745), GFP_KERNEL); + if (!max96745) + return -ENOMEM; + + max96745->muxc = i2c_mux_alloc(client->adapter, dev, nr, 0, + I2C_MUX_LOCKED, max96745_select, NULL); + if (!max96745->muxc) + return -ENOMEM; + + max96745->dev = dev; + i2c_set_clientdata(client, max96745); + + max96745->regmap = devm_regmap_init_i2c(client, &max96745_regmap_config); + if (IS_ERR(max96745->regmap)) + return dev_err_probe(dev, PTR_ERR(max96745->regmap), + "failed to initialize regmap"); + + max96745->enable_gpio = devm_gpiod_get_optional(dev, "enable", + GPIOD_ASIS); + if (IS_ERR(max96745->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(max96745->enable_gpio), + "failed to get enable GPIO\n"); + + max96745->lock_gpio = devm_gpiod_get_optional(dev, "lock", GPIOD_IN); + if (IS_ERR(max96745->lock_gpio)) + return dev_err_probe(dev, PTR_ERR(max96745->lock_gpio), + "failed to get lock GPIO\n"); + + ret = max96745_power_on(max96745); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, max96745_power_off, max96745); + if (ret) + return ret; + + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, max96745_devs, + ARRAY_SIZE(max96745_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(max96745->muxc, 0, nr, 0); + if (ret) { + i2c_mux_del_adapters(max96745->muxc); + return ret; + } + } + + return 0; +} + +static int max96745_i2c_remove(struct i2c_client *client) +{ + struct max96745 *max96745 = i2c_get_clientdata(client); + + i2c_mux_del_adapters(max96745->muxc); + + return 0; +} + +static void max96745_i2c_shutdown(struct i2c_client *client) +{ + struct max96745 *max96745 = i2c_get_clientdata(client); + + max96745_power_off(max96745); +} + +static const struct of_device_id max96745_of_match[] = { + { .compatible = "maxim,max96745", }, + {} +}; +MODULE_DEVICE_TABLE(of, max96745_of_match); + +static struct i2c_driver max96745_i2c_driver = { + .driver = { + .name = "max96745", + .of_match_table = max96745_of_match, + }, + .probe_new = max96745_i2c_probe, + .remove = max96745_i2c_remove, + .shutdown = max96745_i2c_shutdown, +}; + +module_i2c_driver(max96745_i2c_driver); + +MODULE_AUTHOR("Wyon Bi "); +MODULE_DESCRIPTION("Maxim MAX96745 MFD driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/max96745.h b/include/linux/mfd/max96745.h new file mode 100644 index 000000000000..acbe64b945e3 --- /dev/null +++ b/include/linux/mfd/max96745.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Defining registers address and its bit definitions of MAX96745 + * + * Copyright (c) 2022 Rockchip Electronics Co. Ltd. + */ + +#ifndef _MFD_MAX96745_H_ +#define _MFD_MAX96745_H_ + +#include + +#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)) + +/* 0010h */ +#define RESET_ALL BIT(7) +#define SLEEP BIT(3) + +/* 0013h */ +#define LOCKED BIT(3) +#define ERROR BIT(2) + +/* 0028h, 0032h */ +#define LINK_EN BIT(7) + +/* 0029h, 0033h */ +#define RESET_LINK BIT(0) +#define RESET_ONESHOT BIT(1) + +/* 002Ah, 0034h */ +#define LINK_LOCKED BIT(0) + +/* 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_TYPEC 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) + +/* 7000h */ +#define LINK_ENABLE BIT(0) + +/* 7070h */ +#define MAX_LANE_COUNT GENMASK(7, 0) + +/* 7074h */ +#define MAX_LINK_RATE GENMASK(7, 0) + +#endif /* _MFD_MAX96745_H_ */