/* The LED lines are open drain outputs ... a FET pulls to GND, so an *externalpullupisneeded.WecouldalsoexposetheintegratedPWM *asaLEDbrightnesscontrol;weinitializeitas"alwayson".
*/ staticint twl4030_led_set_value(int led, int value)
{
u8 mask = LEDEN_LEDAON | LEDEN_LEDAPWM;
if (led)
mask <<= 1;
if (value)
cached_leden &= ~mask; else
cached_leden |= mask;
staticint twl_request(struct gpio_chip *chip, unsigned offset)
{ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip); int status = 0;
mutex_lock(&priv->mutex);
/* Support the two LED outputs as output-only GPIOs. */ if (offset >= TWL4030_GPIO_MAX) {
u8 ledclr_mask = LEDEN_LEDAON | LEDEN_LEDAEXT
| LEDEN_LEDAPWM | LEDEN_PWM_LENGTHA;
u8 reg = TWL4030_PWMAON_REG;
/* initialize PWM to always-drive */ /* Configure PWM OFF register first */
status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg + 1); if (status < 0) goto done;
/* Followed by PWM ON register */
status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg); if (status < 0) goto done;
/* init LED to not-driven (high) */
status = twl_i2c_read_u8(TWL4030_MODULE_LED, &cached_leden,
TWL4030_LED_LEDEN_REG); if (status < 0) goto done;
cached_leden &= ~ledclr_mask;
status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
TWL4030_LED_LEDEN_REG); if (status < 0) goto done;
status = 0; goto done;
}
/* on first use, turn GPIO module "on" */ if (!priv->usage_count) { struct twl4030_gpio_platform_data *pdata;
u8 value = MASK_GPIO_CTRL_GPIO_ON;
/* optionally have the first two GPIOs switch vMMC1 *andvMMC2powersuppliesbasedoncardpresence.
*/
pdata = dev_get_platdata(chip->parent); if (pdata)
value |= pdata->mmc_cd & 0x03;
status = gpio_twl4030_write(REG_GPIO_CTRL, value);
}
done: if (!status)
priv->usage_count |= BIT(offset);
mutex_lock(&priv->mutex); if (offset < TWL4030_GPIO_MAX)
ret = twl4030_set_gpio_direction(offset, 1); else
ret = -EINVAL; /* LED outputs can't be set as input */
if (!ret)
priv->direction &= ~BIT(offset);
mutex_unlock(&priv->mutex);
return ret;
}
staticint twl_get(struct gpio_chip *chip, unsigned offset)
{ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip); int ret; int status = 0;
mutex_lock(&priv->mutex); if (!(priv->usage_count & BIT(offset))) {
ret = -EPERM; goto out;
}
if (priv->direction & BIT(offset))
status = priv->out_state & BIT(offset); else
status = twl4030_get_gpio_datain(offset);
ret = (status < 0) ? status : !!status;
out:
mutex_unlock(&priv->mutex); return ret;
}
staticint twl_set(struct gpio_chip *chip, unsignedint offset, int value)
{ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip); int ret;
mutex_lock(&priv->mutex); if (offset < TWL4030_GPIO_MAX)
ret = twl4030_set_gpio_dataout(offset, value); else
ret = twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
if (value)
priv->out_state |= BIT(offset); else
priv->out_state &= ~BIT(offset);
mutex_unlock(&priv->mutex);
return ret;
}
staticint twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
{ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip); int ret = 0;
mutex_lock(&priv->mutex); if (offset < TWL4030_GPIO_MAX) {
ret = twl4030_set_gpio_direction(offset, 0); if (ret) {
mutex_unlock(&priv->mutex); return ret;
}
}
/* For most pins, a pulldown was enabled by default. *Weshouldhavedatathat'sspecifictothisboard.
*/ for (gpio_bit = 1, i = 0; i < 5; i++) {
u8 bit_mask; unsigned j;
d = gpiochip_request_own_desc(&priv->gpio_chip, 2, "wlan pwr",
GPIO_ACTIVE_HIGH,
GPIOD_OUT_HIGH); if (IS_ERR(d)) return dev_err_probe(&pdev->dev, PTR_ERR(d), "unable to hog wlan pwr GPIO\n");
gpiod_export(d, 0);
ret = devm_add_action_or_reset(&pdev->dev, gpio_twl4030_power_off_action, d); if (ret) return dev_err_probe(&pdev->dev, ret, "failed to install power off handler\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.