From patchwork Fri Jun 29 08:22:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kunihiko Hayashi X-Patchwork-Id: 140529 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp554036ljj; Fri, 29 Jun 2018 01:22:24 -0700 (PDT) X-Google-Smtp-Source: AAOMgpcJXlWPvUdGJbP7OMuydZGSp5+fswJ5zg4a+VLHgIIvzZa8B/FUHTtLwCFU/OBUh3YVVpZ9 X-Received: by 2002:a65:5288:: with SMTP id y8-v6mr10335365pgp.284.1530260544532; Fri, 29 Jun 2018 01:22:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530260544; cv=none; d=google.com; s=arc-20160816; b=YJVOTv0HpkgKONo77cjimbZM467GMU6Z97KUJ3NtVH3huIW0FCf+CfMbo2f1f8Ke7W EYTUfqUxT6/OOijmoczgq28DiYbPVV3p6t9Zw5ggCHah2N2HpzYaBxjrGmOUPLMoMrO1 6mBJiyOQzGC6k6c27MQb7Xvp+9mZ/K/21RtHj5XhB0/KNDB6OyYMym8JYDFyBT22McCR hVXMeo8pTLvXYCN+EbkV5ZD9mX/ZJNMfBkuq34l4FhfBKw6jkFXo6WPtW0krTqxGT2WV 0WLwEHgU1YhBz49q8I4JW3gxK8Qs+pj2QpdzJ5i6ZJf7a+Rvkjk5uvWbd/jdbPp+31w8 XL1w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=K/nrWkoWmQvKdvOMtfhtgB5IjeyUMVX/uHDVo3jjoXc=; b=PkebE8QQdHZV8+pNj1fQn1cvqtfEgKQpwc8vBioL0YScHKMb00DEDaUg4QyYWrloK5 a+D3+SIYO4JmSWTPl1QXY7bFrZXQ/Us5Eb4isMPdM3eBuguKk4oOMjngRCZRFN2udzTO efdV06QwkndfFlkq8X7dhhrnYfUJ+m078AwqvV56DNtY11/2oLyEh7n78Y4vKR6igZ+1 vD4ch11o2lMwyUP4qpIY+W5n3lfECZKfwkBkF0xFVWcGSjbI+I1MMYMUB18wyr4InD1v wQLT4VGIQ7/j3+YTNciSmZlSp/Jwm0E15D9QD2YljBBrTy7ctKalRmTjdmwLrVKA9Zt5 44PQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a186-v6si7777493pgc.453.2018.06.29.01.22.24; Fri, 29 Jun 2018 01:22:24 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934450AbeF2IWV (ORCPT + 5 others); Fri, 29 Jun 2018 04:22:21 -0400 Received: from mx.socionext.com ([202.248.49.38]:42666 "EHLO mx.socionext.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935049AbeF2IWT (ORCPT ); Fri, 29 Jun 2018 04:22:19 -0400 Received: from unknown (HELO iyokan-ex.css.socionext.com) ([172.31.9.54]) by mx.socionext.com with ESMTP; 29 Jun 2018 17:22:18 +0900 Received: from mail.mfilter.local (m-filter-2 [10.213.24.62]) by iyokan-ex.css.socionext.com (Postfix) with ESMTP id 292AE60034; Fri, 29 Jun 2018 17:22:18 +0900 (JST) Received: from 172.31.9.51 (172.31.9.51) by m-FILTER with ESMTP; Fri, 29 Jun 2018 17:22:18 +0900 Received: from plum.e01.socionext.com (unknown [10.213.132.32]) by kinkan.css.socionext.com (Postfix) with ESMTP id 9859F1A120B; Fri, 29 Jun 2018 17:22:17 +0900 (JST) From: Kunihiko Hayashi To: Liam Girdwood , Mark Brown , Rob Herring , Mark Rutland , Masahiro Yamada Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Masami Hiramatsu , Jassi Brar , Kunihiko Hayashi Subject: [PATCH 1/2] dt-bindings: regulator: add DT bindings for UniPhier regulator Date: Fri, 29 Jun 2018 17:22:12 +0900 Message-Id: <1530260533-19415-2-git-send-email-hayashi.kunihiko@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1530260533-19415-1-git-send-email-hayashi.kunihiko@socionext.com> References: <1530260533-19415-1-git-send-email-hayashi.kunihiko@socionext.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add DT bindings for regulators implemented in UniPhier SoCs. Signed-off-by: Kunihiko Hayashi --- .../bindings/regulator/uniphier-regulator.txt | 54 ++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/uniphier-regulator.txt -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/Documentation/devicetree/bindings/regulator/uniphier-regulator.txt b/Documentation/devicetree/bindings/regulator/uniphier-regulator.txt new file mode 100644 index 0000000..cbc0f6a --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/uniphier-regulator.txt @@ -0,0 +1,54 @@ +Socionext UniPhier Regulator Controller + +This describes the devicetree bindings for regulator controller implemented +on Socionext UniPhier SoCs. + +USB3 Controller +--------------- + +Required properties: +- compatible: Should be + "socionext,uniphier-pro4-usb3-regulator" - for Pro4 SoC + "socionext,uniphier-pxs2-usb3-regulator" - for PXs2 SoC + "socionext,uniphier-ld20-usb3-regulator" - for LD20 SoC + "socionext,uniphier-pxs3-usb3-regulator" - for PXs3 SoC +- reg: Specifies offset and length of the register set for the device. +- clocks: A list of phandles to the clock gate for USB3 glue layer. + According to the clock-names, appropriate clocks are required. +- clock-names: Should contain + "gio", "link" - for Pro4 SoC + "link" - for others +- resets: A list of phandles to the reset control for USB3 glue layer. + According to the reset-names, appropriate resets are required. +- reset-names: Should contain + "gio", "link" - for Pro4 SoC + "link" - for others + +See Documentation/devicetree/bindings/regulator/regulator.txt +for more details about the regulator properties. + +Example: + + usb-glue@65b00000 { + compatible = "socionext,uniphier-ld20-dwc3-glue", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x65b00000 0x400>; + + usb_vbus0: regulators@100 { + compatible = "socionext,uniphier-ld20-usb3-regulator"; + reg = <0x100 0x10>; + clock-names = "link"; + clocks = <&sys_clk 14>; + reset-names = "link"; + resets = <&sys_rst 14>; + }; + + phy { + ... + phy-supply = <&usb_vbus0>; + }; + + other nodes ... + }; From patchwork Fri Jun 29 08:22:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kunihiko Hayashi X-Patchwork-Id: 140531 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp554397ljj; Fri, 29 Jun 2018 01:22:55 -0700 (PDT) X-Google-Smtp-Source: AAOMgpd4BJc3hl9Xcn5IuhKQAPxI8PPWpTR8WRELrT0ZDegBtfXFxVUsuXLsI1upsWo5mAWAJi0l X-Received: by 2002:a62:5e06:: with SMTP id s6-v6mr13468455pfb.253.1530260574895; Fri, 29 Jun 2018 01:22:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530260574; cv=none; d=google.com; s=arc-20160816; b=JPtyzNcz0jCqduZBe4lMswbf+oGSTXweLYUyT6+Mf+ebw4kGoq9jsh6uaCnN31bYAx jtkF7DOkGLJLNEqxPhW8cZGRXIbqXO+SLAZhRVQclbWIwo+Mbr+iZm0PWIU6iSx2EAyJ v8GK9IFm7+7dmDYiwmsBioynogfi1r8beFEgot0NFRiZqMEmylBd687VmCK5ZjEgGxtz ms8glFhhJ7+8KebOfzPz6TnmLgoaT5IbUTdgVb7W9ruNOSDFzIwj7/JppYXWtRL7wzjE vi8foX72ZTh81ghxPn2iMZTb3Z5YNii7BYMEYsq4/IhZABoEsKO5v9pita7SU5KtkWbc TSbQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=CPW8k191Zg8dqoAGEiLdoKzUymjby6jv4xHhZ5DmZe8=; b=jDwLPYqVo00YLF1LlyhqPzTRfftySAUwRJMqQd6smdIVEnlgfQRNucTq0Wsga+IKt7 qjAwXkXsxVHo+ib7PGMm+79+Nhr7W3cPcISpX5wrVfo0s+l71ZVHx8sGle8txJFqt50P xfnCbxe14FPdM4jtnUmCqQ4ey8p8NM5sm+TkwjMSSYOCR13GPOck1SBaz32Ybkn0FAAG 6pbW9YumzkmxsZldVsgvuPCo+PlXxSLIKDV3t1y/sDXhjUxQSe915EDNj1gl+qNQEqn9 tkWy9bVueouoCeWOJX4qKg0SPvvgt/gNUG3Qgxunt37IbGPVehUr7yheIKQTqELwt65w 2XEA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g9-v6si8250366plt.232.2018.06.29.01.22.54; Fri, 29 Jun 2018 01:22:54 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935049AbeF2IWw (ORCPT + 5 others); Fri, 29 Jun 2018 04:22:52 -0400 Received: from mx.socionext.com ([202.248.49.38]:42660 "EHLO mx.socionext.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935051AbeF2IWU (ORCPT ); Fri, 29 Jun 2018 04:22:20 -0400 Received: from unknown (HELO iyokan-ex.css.socionext.com) ([172.31.9.54]) by mx.socionext.com with ESMTP; 29 Jun 2018 17:22:18 +0900 Received: from mail.mfilter.local (m-filter-2 [10.213.24.62]) by iyokan-ex.css.socionext.com (Postfix) with ESMTP id 2E74960034; Fri, 29 Jun 2018 17:22:19 +0900 (JST) Received: from 172.31.9.51 (172.31.9.51) by m-FILTER with ESMTP; Fri, 29 Jun 2018 17:22:19 +0900 Received: from plum.e01.socionext.com (unknown [10.213.132.32]) by kinkan.css.socionext.com (Postfix) with ESMTP id B79901A120B; Fri, 29 Jun 2018 17:22:18 +0900 (JST) From: Kunihiko Hayashi To: Liam Girdwood , Mark Brown , Rob Herring , Mark Rutland , Masahiro Yamada Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Masami Hiramatsu , Jassi Brar , Kunihiko Hayashi Subject: [PATCH 2/2] regulator: uniphier: add regulator driver for UniPhier SoC Date: Fri, 29 Jun 2018 17:22:13 +0900 Message-Id: <1530260533-19415-3-git-send-email-hayashi.kunihiko@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1530260533-19415-1-git-send-email-hayashi.kunihiko@socionext.com> References: <1530260533-19415-1-git-send-email-hayashi.kunihiko@socionext.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Initial commit to add support for regulators implemented in UniPhier SoCs. This supports USB VBUS only. Signed-off-by: Kunihiko Hayashi --- drivers/regulator/Kconfig | 8 ++ drivers/regulator/Makefile | 1 + drivers/regulator/uniphier-regulator.c | 251 +++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 drivers/regulator/uniphier-regulator.c -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 097f617..7f7ad0d 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -932,6 +932,14 @@ config REGULATOR_TWL4030 This driver supports the voltage regulators provided by this family of companion chips. +config REGULATOR_UNIPHIER + tristate "UniPhier regulator driver" + depends on ARCH_UNIPHIER || COMPILE_TEST + depends on OF && MFD_SYSCON + default ARCH_UNIPHIER + help + Support for regulators implemented on Socionext UniPhier SoCs. + config REGULATOR_VCTRL tristate "Voltage controlled regulators" depends on OF diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 590674f..c0dd281 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -116,6 +116,7 @@ obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-regulator.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o +obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o diff --git a/drivers/regulator/uniphier-regulator.c b/drivers/regulator/uniphier-regulator.c new file mode 100644 index 0000000..b1f2649 --- /dev/null +++ b/drivers/regulator/uniphier-regulator.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Regulator controller driver for UniPhier SoC + * Copyright 2018 Socionext Inc. + * Author: Kunihiko Hayashi + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_CLKS 2 +#define MAX_RSTS 2 + +struct uniphier_regulator_soc_data { + const char *clock_names[MAX_CLKS]; + const char *reset_names[MAX_RSTS]; + const struct regulator_desc *desc; +}; + +struct uniphier_regulator_priv { + void __iomem *base; + int nclks; + struct clk *clk[MAX_CLKS]; + int nrsts; + struct reset_control *rst[MAX_RSTS]; + const struct uniphier_regulator_soc_data *data; +}; + +static int uniphier_regulator_enable(struct regulator_dev *rdev) +{ + struct uniphier_regulator_priv *priv = rdev_get_drvdata(rdev); + u32 val; + + val = readl_relaxed(priv->base + rdev->desc->enable_reg); + val &= ~rdev->desc->enable_mask; + val |= rdev->desc->enable_val; + writel_relaxed(val, priv->base + rdev->desc->enable_reg); + + return 0; +} + +static int uniphier_regulator_disable(struct regulator_dev *rdev) +{ + struct uniphier_regulator_priv *priv = rdev_get_drvdata(rdev); + u32 val; + + val = readl_relaxed(priv->base + rdev->desc->enable_reg); + val &= ~rdev->desc->enable_mask; + val |= rdev->desc->disable_val; + writel_relaxed(val, priv->base + rdev->desc->enable_reg); + + return 0; +} + +static int uniphier_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct uniphier_regulator_priv *priv = rdev_get_drvdata(rdev); + u32 val; + int ret = -EINVAL; + + val = readl(priv->base + rdev->desc->enable_reg); + val &= rdev->desc->enable_mask; + + if (val == rdev->desc->enable_val) + ret = 1; + else if (val == rdev->desc->disable_val) + ret = 0; + + return ret; +} + +static struct regulator_ops uniphier_regulator_ops = { + .enable = uniphier_regulator_enable, + .disable = uniphier_regulator_disable, + .is_enabled = uniphier_regulator_is_enabled, +}; + +static int uniphier_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uniphier_regulator_priv *priv; + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct resource *res; + const char *name; + int i, ret, nc, nr; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = of_device_get_match_data(dev); + if (WARN_ON(!priv->data)) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + for (i = 0; i < MAX_CLKS; i++) { + name = priv->data->clock_names[i]; + if (!name) + break; + priv->clk[i] = devm_clk_get(dev, name); + if (IS_ERR(priv->clk[i])) + return PTR_ERR(priv->clk[i]); + priv->nclks++; + } + + for (i = 0; i < MAX_RSTS; i++) { + name = priv->data->reset_names[i]; + if (!name) + break; + priv->rst[i] = devm_reset_control_get_shared(dev, name); + if (IS_ERR(priv->rst[i])) + return PTR_ERR(priv->rst[i]); + priv->nrsts++; + } + + for (nc = 0; nc < priv->nclks; nc++) { + ret = clk_prepare_enable(priv->clk[nc]); + if (ret) + goto out_clk_disable; + } + + for (nr = 0; nr < priv->nrsts; nr++) { + ret = reset_control_deassert(priv->rst[nr]); + if (ret) + goto out_rst_assert; + } + + /* Register UniPhier regulator */ + config.dev = dev; + config.driver_data = priv; + config.of_node = dev->of_node; + config.init_data = of_get_regulator_init_data(dev, dev->of_node, + priv->data->desc); + rdev = devm_regulator_register(dev, priv->data->desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + goto out_rst_assert; + } + + platform_set_drvdata(pdev, priv); + + return 0; + +out_rst_assert: + while (nr--) + reset_control_assert(priv->rst[nr]); +out_clk_disable: + while (nc--) + clk_disable_unprepare(priv->clk[nc]); + + return ret; +} + +static int uniphier_regulator_remove(struct platform_device *pdev) +{ + struct uniphier_regulator_priv *priv = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < priv->nrsts; i++) + reset_control_assert(priv->rst[i]); + for (i = 0; i < priv->nclks; i++) + clk_disable_unprepare(priv->clk[i]); + + return 0; +} + +/* USB3 controller data */ +#define USB3VBUS_OFFSET 0x0 +#define USB3VBUS_REG BIT(4) +#define USB3VBUS_REG_EN BIT(3) +static const struct regulator_desc uniphier_usb3_regulator_desc = { + .name = "vbus", + .of_match = of_match_ptr("vbus"), + .ops = &uniphier_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = USB3VBUS_OFFSET, + .enable_mask = USB3VBUS_REG_EN | USB3VBUS_REG, + .enable_val = USB3VBUS_REG_EN | USB3VBUS_REG, + .disable_val = USB3VBUS_REG_EN, +}; + +static const struct uniphier_regulator_soc_data uniphier_pro4_usb3_data = { + .clock_names = { "gio", "link", }, + .reset_names = { "gio", "link", }, + .desc = &uniphier_usb3_regulator_desc, +}; + +static const struct uniphier_regulator_soc_data uniphier_pxs2_usb3_data = { + .clock_names = { "link", }, + .reset_names = { "link", }, + .desc = &uniphier_usb3_regulator_desc, +}; + +static const struct uniphier_regulator_soc_data uniphier_ld20_usb3_data = { + .clock_names = { "link", }, + .reset_names = { "link", }, + .desc = &uniphier_usb3_regulator_desc, +}; + +static const struct uniphier_regulator_soc_data uniphier_pxs3_usb3_data = { + .clock_names = { "link", }, + .reset_names = { "link", }, + .desc = &uniphier_usb3_regulator_desc, +}; + +static const struct of_device_id uniphier_regulator_match[] = { + /* USB VBUS */ + { + .compatible = "socionext,uniphier-pro4-usb3-regulator", + .data = &uniphier_pro4_usb3_data, + }, + { + .compatible = "socionext,uniphier-pxs2-usb3-regulator", + .data = &uniphier_pxs2_usb3_data, + }, + { + .compatible = "socionext,uniphier-ld20-usb3-regulator", + .data = &uniphier_ld20_usb3_data, + }, + { + .compatible = "socionext,uniphier-pxs3-usb3-regulator", + .data = &uniphier_pxs3_usb3_data, + }, + { /* Sentinel */ }, +}; + +static struct platform_driver uniphier_regulator_driver = { + .probe = uniphier_regulator_probe, + .remove = uniphier_regulator_remove, + .driver = { + .name = "uniphier-regulator", + .of_match_table = uniphier_regulator_match, + }, +}; +module_platform_driver(uniphier_regulator_driver); + +MODULE_AUTHOR("Kunihiko Hayashi "); +MODULE_DESCRIPTION("UniPhier Regulator Controller Driver"); +MODULE_LICENSE("GPL");