@@ -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;
The deserializer has GPIOs that can be used for various purposes. Add support for gpiochip. Signed-off-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com> --- drivers/staging/media/max96712/max96712.c | 140 ++++++++++++++++++++++ 1 file changed, 140 insertions(+)