static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev, unsigned int timeout) { struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); struct wm831x *wm831x = driver_data->wm831x; int ret, i; for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) if (wm831x_wdt_cfgs[i].time == timeout) break; if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) return -EINVAL; ret = wm831x_reg_unlock(wm831x); if (ret == 0) { ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, WM831X_WDOG_TO_MASK, wm831x_wdt_cfgs[i].val); wm831x_reg_lock(wm831x); } else { dev_err(wm831x->dev, "Failed to unlock security key: %d\n", ret); } wdt_dev->timeout = timeout; return ret; }
static int wm831x_wdt_stop(struct wm831x *wm831x) { int ret; mutex_lock(&wdt_mutex); ret = wm831x_reg_unlock(wm831x); if (ret == 0) { ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, WM831X_WDOG_ENA, 0); wm831x_reg_lock(wm831x); } else { dev_err(wm831x->dev, "Failed to unlock security key: %d\n", ret); } mutex_unlock(&wdt_mutex); return ret; }
static int wm831x_wdt_ping(struct watchdog_device *wdt_dev) { struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); struct wm831x *wm831x = driver_data->wm831x; int ret; u16 reg; mutex_lock(&driver_data->lock); if (driver_data->update_gpio) { gpio_set_value_cansleep(driver_data->update_gpio, driver_data->update_state); driver_data->update_state = !driver_data->update_state; ret = 0; goto out; } reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); if (!(reg & WM831X_WDOG_RST_SRC)) { dev_err(wm831x->dev, "Hardware watchdog update unsupported\n"); ret = -EINVAL; goto out; } reg |= WM831X_WDOG_RESET; ret = wm831x_reg_unlock(wm831x); if (ret == 0) { ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg); wm831x_reg_lock(wm831x); } else { dev_err(wm831x->dev, "Failed to unlock security key: %d\n", ret); } out: mutex_unlock(&driver_data->lock); return ret; }
static int wm831x_wdt_kick(struct wm831x *wm831x) { int ret; u16 reg; mutex_lock(&wdt_mutex); if (update_gpio) { gpio_set_value_cansleep(update_gpio, update_state); update_state = !update_state; ret = 0; goto out; } reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); if (!(reg & WM831X_WDOG_RST_SRC)) { dev_err(wm831x->dev, "Hardware watchdog update unsupported\n"); ret = -EINVAL; goto out; } reg |= WM831X_WDOG_RESET; ret = wm831x_reg_unlock(wm831x); if (ret == 0) { ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg); wm831x_reg_lock(wm831x); } else { dev_err(wm831x->dev, "Failed to unlock security key: %d\n", ret); } out: mutex_unlock(&wdt_mutex); return ret; }
static int wm831x_wdt_stop(struct watchdog_device *wdt_dev) { struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); struct wm831x *wm831x = driver_data->wm831x; int ret; mutex_lock(&driver_data->lock); ret = wm831x_reg_unlock(wm831x); if (ret == 0) { ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, WM831X_WDOG_ENA, 0); wm831x_reg_lock(wm831x); } else { dev_err(wm831x->dev, "Failed to unlock security key: %d\n", ret); } mutex_unlock(&driver_data->lock); return ret; }
static void wm831x_config_battery(struct wm831x *wm831x) { struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data; struct wm831x_battery_pdata *pdata; int ret, reg1, reg2, reg3; if (!wm831x_pdata || !wm831x_pdata->battery) { dev_warn(wm831x->dev, "No battery charger configuration\n"); return; } pdata = wm831x_pdata->battery; reg1 = 0; reg2 = 0; reg3 = 0; if (!pdata->enable) { dev_info(wm831x->dev, "Battery charger disabled\n"); return; } reg1 |= WM831X_CHG_ENA; if (pdata->off_mask) reg2 |= WM831X_CHG_OFF_MSK; if (pdata->fast_enable) reg1 |= WM831X_CHG_FAST; wm831x_battey_apply_config(wm831x, trickle_ilims, ARRAY_SIZE(trickle_ilims), pdata->trickle_ilim, ®2, "trickle charge current limit", "mA"); wm831x_battey_apply_config(wm831x, vsels, ARRAY_SIZE(vsels), pdata->vsel, ®2, "target voltage", "mV"); wm831x_battey_apply_config(wm831x, fast_ilims, ARRAY_SIZE(fast_ilims), pdata->fast_ilim, ®2, "fast charge current limit", "mA"); wm831x_battey_apply_config(wm831x, eoc_iterms, ARRAY_SIZE(eoc_iterms), pdata->eoc_iterm, ®1, "end of charge current threshold", "mA"); wm831x_battey_apply_config(wm831x, chg_times, ARRAY_SIZE(chg_times), pdata->timeout, ®2, "charger timeout", "min"); wm831x_battey_apply_config(wm831x, chg_syslos, ARRAY_SIZE(chg_syslos), pdata->syslo, ®3, "syslo voltage", "mV"); wm831x_battey_apply_config(wm831x, chg_sysoks, ARRAY_SIZE(chg_sysoks), pdata->sysok, ®3, "sysok voltage", "mV"); ret = wm831x_reg_unlock(wm831x); if (ret != 0) { dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret); return; } ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_1, WM831X_CHG_ENA_MASK | WM831X_CHG_FAST_MASK | WM831X_CHG_ITERM_MASK, reg1); if (ret != 0) { dev_err(wm831x->dev, "Failed to set charger control 1: %d\n", ret); } ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_2, WM831X_CHG_OFF_MSK | WM831X_CHG_TIME_MASK | WM831X_CHG_FAST_ILIM_MASK | WM831X_CHG_TRKL_ILIM_MASK | WM831X_CHG_VSEL_MASK, reg2); if (ret != 0) { dev_err(wm831x->dev, "Failed to set charger control 2: %d\n", ret); } ret = wm831x_set_bits(wm831x, WM831X_SYSVDD_CONTROL, WM831X_CHG_SYSLO_MASK | WM831X_CHG_SYSOK_MASK, reg3); if (ret < 0) { dev_err(wm831x->dev, "Failed to set sysvdd control reg: %d\n",ret); } wm831x_reg_lock(wm831x); }
static int wm831x_backlight_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *wm831x_pdata; struct wm831x_backlight_pdata *pdata; struct wm831x_backlight_data *data; struct backlight_device *bl; struct backlight_properties props; int ret, i, max_isel, isink_reg, dcdc_cfg; /* We need platform data */ if (pdev->dev.parent->platform_data) { wm831x_pdata = pdev->dev.parent->platform_data; pdata = wm831x_pdata->backlight; } else { pdata = NULL; } if (!pdata) { dev_err(&pdev->dev, "No platform data supplied\n"); return -EINVAL; } /* Figure out the maximum current we can use */ for (i = 0; i < WM831X_ISINK_MAX_ISEL; i++) { if (wm831x_isinkv_values[i] > pdata->max_uA) break; } if (i == 0) { dev_err(&pdev->dev, "Invalid max_uA: %duA\n", pdata->max_uA); return -EINVAL; } max_isel = i - 1; if (pdata->max_uA != wm831x_isinkv_values[max_isel]) dev_warn(&pdev->dev, "Maximum current is %duA not %duA as requested\n", wm831x_isinkv_values[max_isel], pdata->max_uA); switch (pdata->isink) { case 1: isink_reg = WM831X_CURRENT_SINK_1; dcdc_cfg = 0; break; case 2: isink_reg = WM831X_CURRENT_SINK_2; dcdc_cfg = WM831X_DC4_FBSRC; break; default: dev_err(&pdev->dev, "Invalid ISINK %d\n", pdata->isink); return -EINVAL; } /* Configure the ISINK to use for feedback */ ret = wm831x_reg_unlock(wm831x); if (ret < 0) return ret; ret = wm831x_set_bits(wm831x, WM831X_DC4_CONTROL, WM831X_DC4_FBSRC, dcdc_cfg); wm831x_reg_lock(wm831x); if (ret < 0) return ret; data = kzalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) return -ENOMEM; data->wm831x = wm831x; data->current_brightness = 0; data->isink_reg = isink_reg; props.type = BACKLIGHT_RAW; props.max_brightness = max_isel; bl = backlight_device_register("wm831x", &pdev->dev, data, &wm831x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); kfree(data); return PTR_ERR(bl); } bl->props.brightness = max_isel; platform_set_drvdata(pdev, bl); /* Disable the DCDC if it was started so we can bootstrap */ wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, WM831X_DC4_ENA, 0); backlight_update_status(bl); return 0; }
static int __devinit wm831x_wdt_probe(struct platform_device *pdev) { struct wm831x_pdata *chip_pdata; struct wm831x_watchdog_pdata *pdata; int reg, ret; if (wm831x) { dev_err(&pdev->dev, "wm831x watchdog already registered\n"); return -EBUSY; } wm831x = dev_get_drvdata(pdev->dev.parent); ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG); if (ret < 0) { dev_err(wm831x->dev, "Failed to read watchdog status: %d\n", ret); goto err; } reg = ret; if (reg & WM831X_WDOG_DEBUG) dev_warn(wm831x->dev, "Watchdog is paused\n"); /* Apply any configuration */ if (pdev->dev.parent->platform_data) { chip_pdata = pdev->dev.parent->platform_data; pdata = chip_pdata->watchdog; } else { pdata = NULL; } if (pdata) { reg &= ~(WM831X_WDOG_SECACT_MASK | WM831X_WDOG_PRIMACT_MASK | WM831X_WDOG_RST_SRC); reg |= pdata->primary << WM831X_WDOG_PRIMACT_SHIFT; reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT; reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT; if (pdata->update_gpio) { ret = gpio_request(pdata->update_gpio, "Watchdog update"); if (ret < 0) { dev_err(wm831x->dev, "Failed to request update GPIO: %d\n", ret); goto err; } ret = gpio_direction_output(pdata->update_gpio, 0); if (ret != 0) { dev_err(wm831x->dev, "gpio_direction_output returned: %d\n", ret); goto err_gpio; } update_gpio = pdata->update_gpio; /* Make sure the watchdog takes hardware updates */ reg |= WM831X_WDOG_RST_SRC; } ret = wm831x_reg_unlock(wm831x); if (ret == 0) { ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg); wm831x_reg_lock(wm831x); } else { dev_err(wm831x->dev, "Failed to unlock security key: %d\n", ret); goto err_gpio; } } wm831x_wdt_miscdev.parent = &pdev->dev; ret = misc_register(&wm831x_wdt_miscdev); if (ret != 0) { dev_err(wm831x->dev, "Failed to register miscdev: %d\n", ret); goto err_gpio; } return 0; err_gpio: if (update_gpio) { gpio_free(update_gpio); update_gpio = 0; } err: return ret; }
static int wm831x_backlight_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *wm831x_pdata; struct wm831x_backlight_pdata *pdata; struct wm831x_backlight_data *data; struct backlight_device *bl; struct backlight_properties props; int ret, i, max_isel, isink_reg, dcdc_cfg; /* We need platform data */ if (pdev->dev.parent->platform_data) { wm831x_pdata = pdev->dev.parent->platform_data; pdata = wm831x_pdata->backlight; } else { pdata = NULL; } if (!pdata) { dev_err(&pdev->dev, "No platform data supplied\n"); return -EINVAL; } /* Figure out the maximum current we can use */ for (i = 0; i < WM831X_ISINK_MAX_ISEL; i++) { if (wm831x_isinkv_values[i] > pdata->max_uA) break; } if (i == 0) { dev_err(&pdev->dev, "Invalid max_uA: %duA\n", pdata->max_uA); return -EINVAL; } max_isel = i - 1; max_tp = max_isel; if (pdata->max_uA != wm831x_isinkv_values[max_isel]) dev_warn(&pdev->dev, "Maximum current is %duA not %duA as requested\n", wm831x_isinkv_values[max_isel], pdata->max_uA); switch (pdata->isink) { case 1: isink_reg = WM831X_CURRENT_SINK_1; dcdc_cfg = 0; break; case 2: isink_reg = WM831X_CURRENT_SINK_2; dcdc_cfg = WM831X_DC4_FBSRC; break; default: dev_err(&pdev->dev, "Invalid ISINK %d\n", pdata->isink); return -EINVAL; } /* Configure the ISINK to use for feedback */ ret = wm831x_reg_unlock(wm831x); if (ret < 0) return ret; ret = wm831x_set_bits(wm831x, WM831X_DC4_CONTROL, WM831X_DC4_FBSRC, dcdc_cfg); wm831x_reg_lock(wm831x); if (ret < 0) return ret; data = kzalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) return -ENOMEM; data->wm831x = wm831x; data->current_brightness = 0; data->isink_reg = isink_reg; props.max_brightness = max_isel; bl = backlight_device_register("wm831x", &pdev->dev, data, &wm831x_backlight_ops); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); kfree(data); return PTR_ERR(bl); } bl->props.brightness = BL_INIT_VALUE; bl->props.max_brightness= BL_SET; platform_set_drvdata(pdev, bl); #ifdef CONFIG_HAS_EARLYSUSPEND data->early_suspend.level = ~0x0; data->early_suspend.suspend = wm831x_bl_suspend; data->early_suspend.resume = wm831x_bl_resume; register_early_suspend(&data->early_suspend); INIT_DELAYED_WORK(&data->work, wm831x_bl_work); gwm831x_bl = bl; gwm831x_data = data; #endif /* Disable the DCDC if it was started so we can bootstrap */ wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, WM831X_DC4_ENA, 0); //backlight_update_status(bl); schedule_delayed_work(&data->work, msecs_to_jiffies(100)); return 0; }
static void wm831x_config_backup(struct wm831x *wm831x) { struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data; struct wm831x_backup_pdata *pdata; int ret, reg; if (!wm831x_pdata || !wm831x_pdata->backup) { dev_warn(wm831x->dev, "No backup battery charger configuration\n"); return; } pdata = wm831x_pdata->backup; reg = 0; if (pdata->charger_enable) reg |= WM831X_BKUP_CHG_ENA | WM831X_BKUP_BATT_DET_ENA; if (pdata->no_constant_voltage) reg |= WM831X_BKUP_CHG_MODE; switch (pdata->vlim) { case 2500: break; case 3100: reg |= WM831X_BKUP_CHG_VLIM; break; default: dev_err(wm831x->dev, "Invalid backup voltage limit %dmV\n", pdata->vlim); } switch (pdata->ilim) { case 100: break; case 200: reg |= 1; break; case 300: reg |= 2; break; case 400: reg |= 3; break; default: dev_err(wm831x->dev, "Invalid backup current limit %duA\n", pdata->ilim); } ret = wm831x_reg_unlock(wm831x); if (ret != 0) { dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret); return; } ret = wm831x_set_bits(wm831x, WM831X_BACKUP_CHARGER_CONTROL, WM831X_BKUP_CHG_ENA_MASK | WM831X_BKUP_CHG_MODE_MASK | WM831X_BKUP_BATT_DET_ENA_MASK | WM831X_BKUP_CHG_VLIM_MASK | WM831X_BKUP_CHG_ILIM_MASK, reg); if (ret != 0) dev_err(wm831x->dev, "Failed to set backup charger config: %d\n", ret); wm831x_reg_lock(wm831x); }
static int wm831x_wdt_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *chip_pdata; struct wm831x_watchdog_pdata *pdata; struct wm831x_wdt_drvdata *driver_data; struct watchdog_device *wm831x_wdt; int reg, ret, i; ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG); if (ret < 0) { dev_err(wm831x->dev, "Failed to read watchdog status: %d\n", ret); goto err; } reg = ret; if (reg & WM831X_WDOG_DEBUG) dev_warn(wm831x->dev, "Watchdog is paused\n"); driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data), GFP_KERNEL); if (!driver_data) { dev_err(wm831x->dev, "Unable to alloacate watchdog device\n"); ret = -ENOMEM; goto err; } mutex_init(&driver_data->lock); driver_data->wm831x = wm831x; wm831x_wdt = &driver_data->wdt; wm831x_wdt->info = &wm831x_wdt_info; wm831x_wdt->ops = &wm831x_wdt_ops; watchdog_set_nowayout(wm831x_wdt, nowayout); watchdog_set_drvdata(wm831x_wdt, driver_data); reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); reg &= WM831X_WDOG_TO_MASK; for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) if (wm831x_wdt_cfgs[i].val == reg) break; if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) dev_warn(wm831x->dev, "Unknown watchdog timeout: %x\n", reg); else wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time; /* Apply any configuration */ if (pdev->dev.parent->platform_data) { chip_pdata = pdev->dev.parent->platform_data; pdata = chip_pdata->watchdog; } else { pdata = NULL; } if (pdata) { reg &= ~(WM831X_WDOG_SECACT_MASK | WM831X_WDOG_PRIMACT_MASK | WM831X_WDOG_RST_SRC); reg |= pdata->primary << WM831X_WDOG_PRIMACT_SHIFT; reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT; reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT; if (pdata->update_gpio) { ret = gpio_request_one(pdata->update_gpio, GPIOF_DIR_OUT | GPIOF_INIT_LOW, "Watchdog update"); if (ret < 0) { dev_err(wm831x->dev, "Failed to request update GPIO: %d\n", ret); goto err; } driver_data->update_gpio = pdata->update_gpio; /* Make sure the watchdog takes hardware updates */ reg |= WM831X_WDOG_RST_SRC; } ret = wm831x_reg_unlock(wm831x); if (ret == 0) { ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg); wm831x_reg_lock(wm831x); } else { dev_err(wm831x->dev, "Failed to unlock security key: %d\n", ret); goto err_gpio; } } ret = watchdog_register_device(&driver_data->wdt); if (ret != 0) { dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n", ret); goto err_gpio; } dev_set_drvdata(&pdev->dev, driver_data); return 0; err_gpio: if (driver_data->update_gpio) gpio_free(driver_data->update_gpio); err: return ret; }