The deserializer has GPIOs that can be used for various purposes. Add support for gpiochip. Signed-off-by: Laurentiu Palcu <laurentiu.palcu@xxxxxxxxxxx> --- drivers/staging/media/max96712/max96712.c | 140 ++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/drivers/staging/media/max96712/max96712.c b/drivers/staging/media/max96712/max96712.c index ed1d46ea98cb9..307b2f1d3a6be 100644 --- a/drivers/staging/media/max96712/max96712.c +++ b/drivers/staging/media/max96712/max96712.c @@ -7,6 +7,7 @@ */ #include <linux/delay.h> +#include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/i2c-mux.h> #include <linux/module.h> @@ -108,6 +109,41 @@ #define CSI2_LANE_CNT_MASK GENMASK(7, 6) #define CSI2_LANE_CNT_SHIFT 6 +/* GPIO_A: 0 <= gpio < 11 */ +#define MAX96712_GPIO_A_A(gpio) CCI_REG8(0x0300 + (gpio) * 0x03) +#define GPIO_OUT_DIS BIT(0) +#define GPIO_TX_EN_A BIT(1) +#define GPIO_RX_EN_A BIT(2) +#define GPIO_IN BIT(3) +#define GPIO_OUT BIT(4) +#define TX_COMP_EN_A BIT(5) +#define RES_CFG BIT(7) +#define MAX96712_GPIO_A_B(gpio) CCI_REG8(0x0301 + (gpio) * 0x03) +#define GPIO_TX_ID_A_MASK GENMASK(4, 0) +#define GPIO_TX_ID_A_SHIFT 0 +#define OUT_TYPE BIT(5) +#define PULL_UPDN_SEL_MASK GENMASK(7, 6) +#define PULL_UPDN_SEL_SHIFT 6 +#define MAX96712_GPIO_A_C(gpio) CCI_REG8(0x0302 + (gpio) * 0x03) +#define GPIO_RX_ID_A_MASK GENMASK(4, 0) +#define GPIO_RX_ID_A_SHIFT 0 +#define GPIO_RECVED_A BIT(6) +#define OVR_RES_CFG BIT(7) + +/* GPIO_B, GPIO_C, GPIO_D: 0 <= gpio < 11, link: 1, 2, 3 */ +#define MAX96712_GPIO_B(gpio) CCI_REG8(0x0301 + (link) * 0x36 + \ + (gpio) * 0x03) +#define GPIO_TX_ID_MASK GENMASK(4, 0) +#define GPIO_TX_ID_SHIFT 0 +#define GPIO_TX_EN BIT(5) +#define TX_COMP_EN BIT(6) +#define MAX96712_GPIO_C(gpio) CCI_REG8(0x0302 + (link) * 0x36 + \ + (gpio) * 0x03) +#define GPIO_RX_ID_MASK GENMASK(4, 0) +#define GPIO_RX_ID_SHIFT 0 +#define GPIO_RX_EN BIT(5) +#define GPIO_RECVED BIT(6) + /* VRX_PATGEN */ #define MAX96712_VRX_PATGEN_0 CCI_REG8(0x1050) #define VTG_MODE_MASK GENMASK(1, 0) @@ -160,6 +196,8 @@ #define MHZ(f) ((f) * 1000000U) +#define MAX96712_NUM_GPIO 12 + enum max96712_pattern { MAX96712_PATTERN_CHECKERBOARD = 0, MAX96712_PATTERN_GRADIENT, @@ -179,6 +217,8 @@ struct max96712_priv { struct regmap *regmap; struct gpio_desc *gpiod_pwdn; + struct gpio_chip gpio_chip; + struct i2c_mux_core *mux; int mux_chan; @@ -830,6 +870,7 @@ static int max96712_v4l2_register(struct max96712_priv *priv) return ret; } +/* I2C Mux section */ static int max96712_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan) { struct max96712_priv *priv = i2c_mux_priv(muxc); @@ -885,6 +926,101 @@ static int max96712_i2c_init(struct max96712_priv *priv) return ret; } +/* GPIO chip section */ +static int max96712_gpiochip_get(struct gpio_chip *gpiochip, + unsigned int offset) +{ + struct max96712_priv *priv = gpiochip_get_data(gpiochip); + unsigned int val; + int ret; + + ret = regmap_read(priv->regmap, MAX96712_GPIO_A_A(offset), &val); + if (ret) + return ret; + + if (val & GPIO_OUT_DIS) + return !!(val & GPIO_IN); + else + return !!(val & GPIO_OUT); +} + +static void max96712_gpiochip_set(struct gpio_chip *gpiochip, + unsigned int offset, int value) +{ + struct max96712_priv *priv = gpiochip_get_data(gpiochip); + + regmap_update_bits(priv->regmap, MAX96712_GPIO_A_A(offset), GPIO_OUT, + GPIO_OUT); +} + +static int max96712_gpio_get_direction(struct gpio_chip *gpiochip, + unsigned int offset) +{ + struct max96712_priv *priv = gpiochip_get_data(gpiochip); + unsigned int val; + int ret; + + ret = regmap_read(priv->regmap, MAX96712_GPIO_A_A(offset), &val); + if (ret < 0) + return ret; + + return !!(val & GPIO_OUT_DIS); +} + +static int max96712_gpio_direction_out(struct gpio_chip *gpiochip, + unsigned int offset, int value) +{ + struct max96712_priv *priv = gpiochip_get_data(gpiochip); + + return regmap_update_bits(priv->regmap, MAX96712_GPIO_A_A(offset), + GPIO_OUT_DIS | GPIO_OUT, + value ? GPIO_OUT : 0); +} + +static int max96712_gpio_direction_in(struct gpio_chip *gpiochip, + unsigned int offset) +{ + struct max96712_priv *priv = gpiochip_get_data(gpiochip); + + return regmap_update_bits(priv->regmap, MAX96712_GPIO_A_A(offset), + GPIO_OUT_DIS, GPIO_OUT_DIS); +} + +static int max96712_gpiochip_probe(struct max96712_priv *priv) +{ + struct device *dev = &priv->client->dev; + struct gpio_chip *gc = &priv->gpio_chip; + int i, ret = 0; + + gc->label = dev_name(dev); + gc->parent = dev; + gc->owner = THIS_MODULE; + gc->ngpio = MAX96712_NUM_GPIO; + gc->base = -1; + gc->can_sleep = true; + gc->get_direction = max96712_gpio_get_direction; + gc->direction_input = max96712_gpio_direction_in; + gc->direction_output = max96712_gpio_direction_out; + gc->request = gpiochip_generic_request; + gc->set = max96712_gpiochip_set; + gc->get = max96712_gpiochip_get; + gc->of_gpio_n_cells = 2; + + /* Disable GPIO forwarding */ + for (i = 0; i < gc->ngpio; i++) + regmap_update_bits(priv->regmap, MAX96712_GPIO_A_A(i), + GPIO_RX_EN_A | GPIO_TX_EN_A, 0); + + ret = devm_gpiochip_add_data(dev, gc, priv); + if (ret) { + dev_err(dev, "Unable to create gpio_chip\n"); + return ret; + } + + return 0; +} + +/* DT parsing section */ static int max96712_parse_rx_ports(struct max96712_priv *priv, struct device_node *node, struct of_endpoint *ep) { @@ -1061,6 +1197,10 @@ static int max96712_probe(struct i2c_client *client) max96712_mipi_configure(priv); + ret = max96712_gpiochip_probe(priv); + if (ret) + return ret; + ret = max96712_v4l2_register(priv); if (ret) return ret; -- 2.44.1