From owner-svn-src-all@freebsd.org Sat Jun 16 08:25:39 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 9ACFC100E75C; Sat, 16 Jun 2018 08:25:39 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 51B3C796C0; Sat, 16 Jun 2018 08:25:39 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 32CB623D92; Sat, 16 Jun 2018 08:25:39 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w5G8PdUF008040; Sat, 16 Jun 2018 08:25:39 GMT (envelope-from mmel@FreeBSD.org) Received: (from mmel@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w5G8PcE7008038; Sat, 16 Jun 2018 08:25:38 GMT (envelope-from mmel@FreeBSD.org) Message-Id: <201806160825.w5G8PcE7008038@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mmel set sender to mmel@FreeBSD.org using -f From: Michal Meloun Date: Sat, 16 Jun 2018 08:25:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r335249 - head/sys/dev/extres/regulator X-SVN-Group: head X-SVN-Commit-Author: mmel X-SVN-Commit-Paths: head/sys/dev/extres/regulator X-SVN-Commit-Revision: 335249 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 16 Jun 2018 08:25:39 -0000 Author: mmel Date: Sat Jun 16 08:25:38 2018 New Revision: 335249 URL: https://svnweb.freebsd.org/changeset/base/335249 Log: Fix handling of enable counter for shared GPIO line in fixed regulator. For most regulators, the regulator_stop() method can be transformed to regulator disable. But, in some cases, we needs to maintain shared data across multiple regulators (e.g. single GPIO pin which works as enable for multiple regulates). In this case, the implementation of regulator should perform his own enable counting therefore it is necessary to distinguish between the regulator enable/disable method (which increments/decrements enable counter for shared resource) and regulator stop method (which don't affect it). So: - add regnode_stop() method to regulator framework and default it to regnode_enable(..., false, ...) - implement it in regulator_fixed with proper enable counting. While I'm in, also fix handling of always_on property. If any of regulators sharing same GPIO pin have it enabled, then none of them can disable regulator. Tested by: kevans MFC after: 3 weeks Modified: head/sys/dev/extres/regulator/regnode_if.m head/sys/dev/extres/regulator/regulator.c head/sys/dev/extres/regulator/regulator_fixed.c Modified: head/sys/dev/extres/regulator/regnode_if.m ============================================================================== --- head/sys/dev/extres/regulator/regnode_if.m Sat Jun 16 06:23:07 2018 (r335248) +++ head/sys/dev/extres/regulator/regnode_if.m Sat Jun 16 08:25:38 2018 (r335249) @@ -31,6 +31,15 @@ HEADER { struct regnode; } +CODE { + static int + regnode_default_stop(struct regnode *regnode, int *udelay) + { + + return(REGNODE_ENABLE(regnode, false, udelay)); + } +} + # # Initialize regulator # Returns 0 on success or a standard errno value. @@ -80,3 +89,12 @@ METHOD int get_voltage { struct regnode *regnode; int *uvolt; }; + +# +# Stop (shutdown) regulator +# Returns 0 on success or a standard errno value. +# +METHOD int stop { + struct regnode *regnode; + int *udelay; +} DEFAULT regnode_default_stop; Modified: head/sys/dev/extres/regulator/regulator.c ============================================================================== --- head/sys/dev/extres/regulator/regulator.c Sat Jun 16 06:23:07 2018 (r335248) +++ head/sys/dev/extres/regulator/regulator.c Sat Jun 16 08:25:38 2018 (r335249) @@ -636,7 +636,7 @@ regnode_stop(struct regnode *regnode, int depth) /* Disable regulator for each node in chain, starting from consumer */ if ((regnode->enable_cnt == 0) && ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) { - rv = REGNODE_ENABLE(regnode, false, &udelay); + rv = REGNODE_STOP(regnode, &udelay); if (rv != 0) { REGNODE_UNLOCK(regnode); return (rv); @@ -648,7 +648,7 @@ regnode_stop(struct regnode *regnode, int depth) rv = regnode_resolve_parent(regnode); if (rv != 0) return (rv); - if (regnode->parent != NULL) + if (regnode->parent != NULL && regnode->parent->enable_cnt == 0) rv = regnode_stop(regnode->parent, depth + 1); return (rv); } Modified: head/sys/dev/extres/regulator/regulator_fixed.c ============================================================================== --- head/sys/dev/extres/regulator/regulator_fixed.c Sat Jun 16 06:23:07 2018 (r335248) +++ head/sys/dev/extres/regulator/regulator_fixed.c Sat Jun 16 08:25:38 2018 (r335249) @@ -56,6 +56,7 @@ struct gpio_entry { struct gpiobus_pin gpio_pin; int use_cnt; int enable_cnt; + bool always_on; }; static gpio_list_t gpio_list = TAILQ_HEAD_INITIALIZER(gpio_list); static struct mtx gpio_list_mtx; @@ -71,12 +72,14 @@ static int regnode_fixed_init(struct regnode *regnode) static int regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay); static int regnode_fixed_status(struct regnode *regnode, int *status); +static int regnode_fixed_stop(struct regnode *regnode, int *udelay); static regnode_method_t regnode_fixed_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, regnode_fixed_init), REGNODEMETHOD(regnode_enable, regnode_fixed_enable), REGNODEMETHOD(regnode_status, regnode_fixed_status), + REGNODEMETHOD(regnode_stop, regnode_fixed_stop), REGNODEMETHOD_END }; DEFINE_CLASS_1(regnode_fixed, regnode_fixed_class, regnode_fixed_methods, @@ -188,8 +191,6 @@ regnode_fixed_enable(struct regnode *regnode, bool ena dev = regnode_get_device(regnode); *udelay = 0; - if (sc->param->always_on && !enable) - return (0); if (sc->gpio_entry == NULL) return (0); pin = &sc->gpio_entry->gpio_pin; @@ -204,6 +205,8 @@ regnode_fixed_enable(struct regnode *regnode, bool ena if (sc->gpio_entry->enable_cnt >= 1) return (0); } + if (sc->gpio_entry->always_on && !enable) + return (0); if (!sc->param->enable_active_high) enable = !enable; rv = GPIO_PIN_SET(pin->dev, pin->pin, enable); @@ -215,7 +218,43 @@ regnode_fixed_enable(struct regnode *regnode, bool ena return (0); } +/* + * Stop (physicaly shutdown) regulator. + * Take shared GPIO pins in account + */ static int +regnode_fixed_stop(struct regnode *regnode, int *udelay) +{ + device_t dev; + struct regnode_fixed_sc *sc; + struct gpiobus_pin *pin; + int rv; + + sc = regnode_get_softc(regnode); + dev = regnode_get_device(regnode); + + *udelay = 0; + if (sc->gpio_entry == NULL) + return (0); + if (sc->gpio_entry->always_on) + return (0); + pin = &sc->gpio_entry->gpio_pin; + if (sc->gpio_entry->enable_cnt > 0) { + /* Other regulator(s) are enabled. */ + /* XXXX Any diagnostic message? Or error? */ + return (0); + } + rv = GPIO_PIN_SET(pin->dev, pin->pin, + sc->param->enable_active_high ? false: true); + if (rv != 0) { + device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin); + return (rv); + } + *udelay = sc->param->enable_delay; + return (0); +} + +static int regnode_fixed_status(struct regnode *regnode, int *status) { struct regnode_fixed_sc *sc; @@ -264,6 +303,10 @@ regnode_fixed_register(device_t dev, struct regnode_fi device_printf(dev, "Cannot register regulator.\n"); return(ENXIO); } + + if (sc->gpio_entry != NULL) + sc->gpio_entry->always_on |= sc->param->always_on; + return (0); }