diff options
author | Antti Palosaari <crope@iki.fi> | 2012-07-19 21:10:36 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-09-27 14:33:58 -0300 |
commit | 1e8f31f31726148c27de1ff4692c76c9bcff9860 (patch) | |
tree | b593d16c49ae28aec06f8e3d42ca8b70d08a7ea6 /drivers/media/dvb-frontends/cxd2820r_core.c | |
parent | 75aeafc9d0e21222b876990946ef534b384462f1 (diff) |
[media] cxd2820r: use Kernel GPIO for GPIO access
Currently there is LNA behind cxd2820r demodulator GPIO. Use
Kernel GPIO interface to access those GPIOs.
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb-frontends/cxd2820r_core.c')
-rw-r--r-- | drivers/media/dvb-frontends/cxd2820r_core.c | 108 |
1 files changed, 88 insertions, 20 deletions
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index a3656ba67d7..4bd42f20d5b 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -168,30 +168,15 @@ int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val, return cxd2820r_wr_reg(priv, reg, val); } -int cxd2820r_gpio(struct dvb_frontend *fe) +int cxd2820r_gpio(struct dvb_frontend *fe, u8 *gpio) { struct cxd2820r_priv *priv = fe->demodulator_priv; int ret, i; - u8 *gpio, tmp0, tmp1; + u8 tmp0, tmp1; dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, fe->dtv_property_cache.delivery_system); - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - gpio = priv->cfg.gpio_dvbt; - break; - case SYS_DVBT2: - gpio = priv->cfg.gpio_dvbt2; - break; - case SYS_DVBC_ANNEX_AC: - gpio = priv->cfg.gpio_dvbc; - break; - default: - ret = -EINVAL; - goto error; - } - /* update GPIOs only when needed */ if (!memcmp(gpio, priv->gpio, sizeof(priv->gpio))) return 0; @@ -582,9 +567,19 @@ static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe) static void cxd2820r_release(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; dev_dbg(&priv->i2c->dev, "%s\n", __func__); +#ifdef CONFIG_GPIOLIB + /* remove GPIOs */ + if (priv->gpio_chip.label) { + ret = gpiochip_remove(&priv->gpio_chip); + if (ret) + dev_err(&priv->i2c->dev, "%s: gpiochip_remove() " \ + "failed=%d\n", KBUILD_MODNAME, ret); + } +#endif kfree(priv); return; } @@ -599,6 +594,49 @@ static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1); } +#ifdef CONFIG_GPIOLIB +static int cxd2820r_gpio_direction_output(struct gpio_chip *chip, unsigned nr, + int val) +{ + struct cxd2820r_priv *priv = + container_of(chip, struct cxd2820r_priv, gpio_chip); + u8 gpio[GPIO_COUNT]; + + dev_dbg(&priv->i2c->dev, "%s: nr=%d val=%d\n", __func__, nr, val); + + memcpy(gpio, priv->gpio, sizeof(gpio)); + gpio[nr] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | (val << 2); + + return cxd2820r_gpio(&priv->fe, gpio); +} + +static void cxd2820r_gpio_set(struct gpio_chip *chip, unsigned nr, int val) +{ + struct cxd2820r_priv *priv = + container_of(chip, struct cxd2820r_priv, gpio_chip); + u8 gpio[GPIO_COUNT]; + + dev_dbg(&priv->i2c->dev, "%s: nr=%d val=%d\n", __func__, nr, val); + + memcpy(gpio, priv->gpio, sizeof(gpio)); + gpio[nr] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | (val << 2); + + (void) cxd2820r_gpio(&priv->fe, gpio); + + return; +} + +static int cxd2820r_gpio_get(struct gpio_chip *chip, unsigned nr) +{ + struct cxd2820r_priv *priv = + container_of(chip, struct cxd2820r_priv, gpio_chip); + + dev_dbg(&priv->i2c->dev, "%s: nr=%d\n", __func__, nr); + + return (priv->gpio[nr] >> 2) & 0x01; +} +#endif + static const struct dvb_frontend_ops cxd2820r_ops = { .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A }, /* default: DVB-T/T2 */ @@ -645,15 +683,20 @@ static const struct dvb_frontend_ops cxd2820r_ops = { }; struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, - struct i2c_adapter *i2c) + struct i2c_adapter *i2c, int *gpio_chip_base +) { - struct cxd2820r_priv *priv = NULL; + struct cxd2820r_priv *priv; int ret; u8 tmp; priv = kzalloc(sizeof (struct cxd2820r_priv), GFP_KERNEL); - if (!priv) + if (!priv) { + ret = -ENOMEM; + dev_err(&i2c->dev, "%s: kzalloc() failed\n", + KBUILD_MODNAME); goto error; + } priv->i2c = i2c; memcpy(&priv->cfg, cfg, sizeof (struct cxd2820r_config)); @@ -664,10 +707,35 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, if (ret || tmp != 0xe1) goto error; +#ifdef CONFIG_GPIOLIB + /* add GPIOs */ + if (gpio_chip_base) { + priv->gpio_chip.label = KBUILD_MODNAME; + priv->gpio_chip.dev = &priv->i2c->dev; + priv->gpio_chip.owner = THIS_MODULE; + priv->gpio_chip.direction_output = + cxd2820r_gpio_direction_output; + priv->gpio_chip.set = cxd2820r_gpio_set; + priv->gpio_chip.get = cxd2820r_gpio_get; + priv->gpio_chip.base = -1; /* dynamic allocation */ + priv->gpio_chip.ngpio = GPIO_COUNT; + priv->gpio_chip.can_sleep = 1; + ret = gpiochip_add(&priv->gpio_chip); + if (ret) + goto error; + + dev_dbg(&priv->i2c->dev, "%s: gpio_chip.base=%d\n", __func__, + priv->gpio_chip.base); + + *gpio_chip_base = priv->gpio_chip.base; + } +#endif + memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof (struct dvb_frontend_ops)); priv->fe.demodulator_priv = priv; return &priv->fe; error: + dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); kfree(priv); return NULL; } |