From nobody Thu Oct 2 18:27:03 2025 Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 272D6283129 for ; Sat, 13 Sep 2025 21:16:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757798188; cv=none; b=g+8pelyTyy04tn7ddBoY/VGr3zYQQOX4UHZDVnaYtDx7EQJL5eq2EfPoYzFZ/WyIXrpXxczjvBMcwFK5tMLCd0NGXEWmC55bvfhQf5lXId0X9EcocfZHlf6r2awIw0VlmSHxu4CsaBhx7T0ZVaH4w6DDoCcy6ADX6pwkK8lgukY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757798188; c=relaxed/simple; bh=FbsSrDbIsf254X9ygdyJmab114sPqVBUJEm/ZgXYp8k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hJ9/eM00KqCyWFyF2u8+0E/qvXaJsln72UDBlm6kjPoKD8GwAP1VaGURCYPV/5TMJxrgSd6b/x9GJ5Ce4ZAgAEMDPdLUZRUibu5ewjwjKyx86ujILMheCxqpXQkGJaAkzngqY23saTRbmxmv6BdjWuHJg/Zu3AB6i5VyLJlFu3I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=d1E4NQlw; arc=none smtp.client-ip=209.85.128.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="d1E4NQlw" Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-45e03730f83so13826525e9.0 for ; Sat, 13 Sep 2025 14:16:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757798184; x=1758402984; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=hRPSMDhrgBlR28GcWuNEsdGj0gTClNNcrvrMo8tfw8k=; b=d1E4NQlwGwqFQ+WFnRgJY+NevmBkdDUJxOjIgNxpwg/zCJwxo0jwOXYF36yA425h9X 5R+w/DwhaJ1gwHOpolMPsUedXKyEhEvDfANnNEeH20HPYCEGpHKdELDteSho43F40uql pqdqlZsrOOHQ0cEDysNSk/erMEFLIMFezm7KWqFYoNbw5rYLMYiUUFckM9x5nSBUE95w UeqkiYZJ8e8uBVqbpajytEy0gIZr3Vur+D68hwC1f81UMrtfzAcTb/DEgwyGB91f83Rd Ib4hrnrfrEnbR4dC3C3XbPMQp1df8HuJQfIWhGMd1cTjejxJw+BhgBs1d7VQ2ubJaxcW 7heQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757798184; x=1758402984; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=hRPSMDhrgBlR28GcWuNEsdGj0gTClNNcrvrMo8tfw8k=; b=Mtw77mrWKa7qg4PZSxWRPVbaayCgmdW9U3sqZaakhZJzOttH8ozvfMAeorvFajIhim lgE3O2X6YaJxzNcHe6GurotVgVrwsr0W+DeBM7/XK1Hx5jm09NbysXdjqHdJCfY0cUUR o5zgoyn75SYEc2ZIJOpsIWlS+TPpcoPOVbDFF0jSV6UpQdDU1vc5JCNuuKqWSTQTcERT GZkJiJqG0mKvlG5ESqiPD+g6m08mYIeweIXYLfbVDMd8g/kbO/QrhikgLiX9k0Ttewuk e+Ep+Hg+ov6KcmDl1yXxM6DU7ihNXFm3b3zRnCtdt7NfPzLDSY5V3AqTYDvX9Ob0FjYd Hg4A== X-Forwarded-Encrypted: i=1; AJvYcCWeJ4n7w50tSURF5pX0HrHW+wGDn3E3Myj1/0WExwXa4HPz+jqqSNSMRbT5J2aqVnrKpe/Lw9DtCpxtFyo=@vger.kernel.org X-Gm-Message-State: AOJu0YyH78yjC17whQPWcAsYexNhINruCXxjASnndMnLgl89zrg8hPwQ 4//YJIXCfOTFuZ0cOTTV0NyJ5Djx9xhe+2JUapat4Imd3Q//VBc+pOFtaFTerzhs X-Gm-Gg: ASbGnctj7NEbqwAYQgPnMfe0Y6smzIBGPiUyAZRWgXEfGX1zGxWQdVV8X5y1UT6VxlQ pCjUDv44DBA2u2ydMGWFUH86pMmZAtmW2XgI+0b2NRJzfYSgpoxbZPJl81V3VvetIchFdpQYVkO NId4mlmekq02ScG1bozndn7f4nZO1a116/bXSbkXqrtuocMqUKpromvjZUz1bPFiRjpik4Ck70E i79I17iKmXqofnnBqSvgkFgJ9OXRjclBCpHz7DaY1PT4zIAS0H5VObiZCfn9bY4dM+B+Gcy546c J+pL7KDL3wf18gZagXw3N0zexq1eVsaKhyBs2/o5tAIhizovM4pT93eIMadzGDtEToW7Uwa9jvt GKi/NGfsfWGcg5HFbX4y2w8pIB+dZzED/uaefGD45MOaQhwTkplzI X-Google-Smtp-Source: AGHT+IGn5Ct9i7dOW4IgjxA/5Yvs0me0MDivcN7ezFGBgxTgSHfWsOUNBtqLrEb3nQ0wFvqCLJX0Sw== X-Received: by 2002:a05:600c:5248:b0:45d:d9ab:b85a with SMTP id 5b1f17b1804b1-45f211e520bmr76729935e9.7.1757798183876; Sat, 13 Sep 2025 14:16:23 -0700 (PDT) Received: from Radijator.localdomain ([93.140.65.23]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e014ac468sm65403145e9.0.2025.09.13.14.16.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 13 Sep 2025 14:16:23 -0700 (PDT) From: =?utf-8?q?Duje_Mihanovi=C4=87?= Date: Sat, 13 Sep 2025 23:12:49 +0200 Subject: [PATCH v4 2/4] pmdomain: marvell: Add PXA1908 power domains Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250913-pxa1908-genpd-v4-2-55e4cf32f619@dujemihanovic.xyz> References: <20250913-pxa1908-genpd-v4-0-55e4cf32f619@dujemihanovic.xyz> In-Reply-To: <20250913-pxa1908-genpd-v4-0-55e4cf32f619@dujemihanovic.xyz> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Ulf Hansson Cc: David Wronek , Karel Balej , phone-devel@vger.kernel.org, ~postmarketos/upstreaming@lists.sr.ht, linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, =?utf-8?q?Duje_Mihanovi=C4=87?= X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=11858; i=duje@dujemihanovic.xyz; s=20240706; h=from:subject:message-id; bh=s4HrTeVpqN7u98RpTsl8VxYA+1XpjoqSONdA9Q+y97U=; b=owGbwMvMwCW21nBykGv/WmbG02pJDBlH7yv999zI+slIjc9EObVH5coCHm5Ok+YpAr57EmfZc cfLrDjbUcrCIMbFICumyJL73/Ea72eRrduzlxnAzGFlAhnCwMUpABMJYGRkmCh4W+TGlc1BWVxx zN/4Vu/9MMNuduUqbbPrjQuOsy95ksrwz+wuw+KOhiP9F/lWljbmmny+3/t2UR57yLUb+ofvvzr ZxQ8A X-Developer-Key: i=duje@dujemihanovic.xyz; a=openpgp; fpr=6DFF41D60DF314B5B76BA630AD319352458FAD03 From: Duje Mihanovi=C4=87 Marvell's PXA1908 SoC has a few power domains for its VPU, GPU, image processor and DSI PHY. Add a driver to control these. Signed-off-by: Duje Mihanovi=C4=87 --- v4: - Drop usage of &genpd->dev - Macros for poll sleep and timeout delays - Configure domains before registering - Clean up includes v3: - Move driver back to pmdomain subsystem, use auxiliary bus to instantiate the driver - Drop redundant 'struct device' pointer in 'struct pxa1908_pd' - Fix pxa1908_pd_is_on() for DSI domain - Replace usleep_range() with fsleep() - Use dev_err_probe() where sensible v2: - Move to clk subsystem, instantiate the driver from the APMU clock driver - Drop clock handling - Squash MAINTAINERS patch --- MAINTAINERS | 1 + drivers/pmdomain/Kconfig | 1 + drivers/pmdomain/Makefile | 1 + drivers/pmdomain/marvell/Kconfig | 18 ++ drivers/pmdomain/marvell/Makefile | 3 + .../pmdomain/marvell/pxa1908-power-controller.c | 274 +++++++++++++++++= ++++ 6 files changed, 298 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6f1d29c42c2eccf7fad489fd6a9b2c74fb24e4ff..5b0e4767639b24d89fa760020a9= 681e5c2001a6e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2871,6 +2871,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated fo= r non-subscribers) S: Maintained F: arch/arm64/boot/dts/marvell/mmp/ F: drivers/clk/mmp/clk-pxa1908*.c +F: drivers/pmdomain/marvell/ F: include/dt-bindings/clock/marvell,pxa1908.h F: include/dt-bindings/power/marvell,pxa1908-power.h =20 diff --git a/drivers/pmdomain/Kconfig b/drivers/pmdomain/Kconfig index 91f04ace35d4b024fafdf6af4e26a179640eb82f..23076ae90e6641dea8e5dbc851d= 041cd7929cee6 100644 --- a/drivers/pmdomain/Kconfig +++ b/drivers/pmdomain/Kconfig @@ -7,6 +7,7 @@ source "drivers/pmdomain/apple/Kconfig" source "drivers/pmdomain/arm/Kconfig" source "drivers/pmdomain/bcm/Kconfig" source "drivers/pmdomain/imx/Kconfig" +source "drivers/pmdomain/marvell/Kconfig" source "drivers/pmdomain/mediatek/Kconfig" source "drivers/pmdomain/qcom/Kconfig" source "drivers/pmdomain/renesas/Kconfig" diff --git a/drivers/pmdomain/Makefile b/drivers/pmdomain/Makefile index 7030f44a49df9e91b1c9d1b6d12690a6248671fb..ebc802f13eb953db750f5a9507c= aa64c637a957a 100644 --- a/drivers/pmdomain/Makefile +++ b/drivers/pmdomain/Makefile @@ -5,6 +5,7 @@ obj-y +=3D apple/ obj-y +=3D arm/ obj-y +=3D bcm/ obj-y +=3D imx/ +obj-y +=3D marvell/ obj-y +=3D mediatek/ obj-y +=3D qcom/ obj-y +=3D renesas/ diff --git a/drivers/pmdomain/marvell/Kconfig b/drivers/pmdomain/marvell/Kc= onfig new file mode 100644 index 0000000000000000000000000000000000000000..6c4084c826670266b7d948438f6= e6d76acb416e2 --- /dev/null +++ b/drivers/pmdomain/marvell/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only + +menu "Marvell PM Domains" + depends on ARCH_MMP || COMPILE_TEST + +config PXA1908_PM_DOMAINS + tristate "Marvell PXA1908 power domains" + depends on OF + depends on PM + default y if ARCH_MMP && ARM64 + select AUXILIARY_BUS + select MFD_SYSCON + select PM_GENERIC_DOMAINS + select PM_GENERIC_DOMAINS_OF + help + Say Y here to enable support for Marvell PXA1908's power domanis. + +endmenu diff --git a/drivers/pmdomain/marvell/Makefile b/drivers/pmdomain/marvell/M= akefile new file mode 100644 index 0000000000000000000000000000000000000000..22c25013f6c856a2ca01a121e83= 0279ee88eb0ed --- /dev/null +++ b/drivers/pmdomain/marvell/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_PXA1908_PM_DOMAINS) +=3D pxa1908-power-controller.o diff --git a/drivers/pmdomain/marvell/pxa1908-power-controller.c b/drivers/= pmdomain/marvell/pxa1908-power-controller.c new file mode 100644 index 0000000000000000000000000000000000000000..ff5e6e82d3f8df2b373a362e046= 0ccb9e196d9ce --- /dev/null +++ b/drivers/pmdomain/marvell/pxa1908-power-controller.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2025 Duje Mihanovi=C4=87 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* VPU, GPU, ISP */ +#define APMU_PWR_CTRL_REG 0xd8 +#define APMU_PWR_BLK_TMR_REG 0xdc +#define APMU_PWR_STATUS_REG 0xf0 + +/* DSI */ +#define APMU_DEBUG 0x88 +#define DSI_PHY_DVM_MASK BIT(31) + +#define POWER_ON_LATENCY_US 300 +#define POWER_OFF_LATENCY_US 20 +#define POWER_POLL_TIMEOUT_US (25 * USEC_PER_MSEC) +#define POWER_POLL_SLEEP_US 6 + +#define NR_DOMAINS 5 + +#define to_pxa1908_pd(_genpd) container_of(_genpd, struct pxa1908_pd, genp= d) + +struct pxa1908_pd_ctrl { + struct generic_pm_domain *domains[NR_DOMAINS]; + struct genpd_onecell_data onecell_data; + struct regmap *base; + struct device *dev; +}; + +struct pxa1908_pd_data { + u32 reg_clk_res_ctrl; + u32 pwr_state; + u32 hw_mode; + bool keep_on; + int id; +}; + +struct pxa1908_pd { + const struct pxa1908_pd_data data; + struct pxa1908_pd_ctrl *ctrl; + struct generic_pm_domain genpd; + bool initialized; +}; + +static inline bool pxa1908_pd_is_on(struct pxa1908_pd *pd) +{ + struct pxa1908_pd_ctrl *ctrl =3D pd->ctrl; + + return pd->data.id !=3D PXA1908_POWER_DOMAIN_DSI + ? regmap_test_bits(ctrl->base, APMU_PWR_STATUS_REG, pd->data.pwr_state) + : regmap_test_bits(ctrl->base, APMU_DEBUG, DSI_PHY_DVM_MASK); +} + +static int pxa1908_pd_power_on(struct generic_pm_domain *genpd) +{ + struct pxa1908_pd *pd =3D to_pxa1908_pd(genpd); + const struct pxa1908_pd_data *data =3D &pd->data; + struct pxa1908_pd_ctrl *ctrl =3D pd->ctrl; + unsigned int status; + int ret =3D 0; + + regmap_set_bits(ctrl->base, data->reg_clk_res_ctrl, data->hw_mode); + if (data->id !=3D PXA1908_POWER_DOMAIN_ISP) + regmap_write(ctrl->base, APMU_PWR_BLK_TMR_REG, 0x20001fff); + regmap_set_bits(ctrl->base, APMU_PWR_CTRL_REG, data->pwr_state); + + ret =3D regmap_read_poll_timeout(ctrl->base, APMU_PWR_STATUS_REG, status, + status & data->pwr_state, POWER_POLL_SLEEP_US, + POWER_ON_LATENCY_US + POWER_POLL_TIMEOUT_US); + if (ret =3D=3D -ETIMEDOUT) + dev_err(ctrl->dev, "timed out powering on domain '%s'\n", pd->genpd.name= ); + + return ret; +} + +static int pxa1908_pd_power_off(struct generic_pm_domain *genpd) +{ + struct pxa1908_pd *pd =3D to_pxa1908_pd(genpd); + const struct pxa1908_pd_data *data =3D &pd->data; + struct pxa1908_pd_ctrl *ctrl =3D pd->ctrl; + unsigned int status; + int ret; + + regmap_clear_bits(ctrl->base, APMU_PWR_CTRL_REG, data->pwr_state); + + ret =3D regmap_read_poll_timeout(ctrl->base, APMU_PWR_STATUS_REG, status, + !(status & data->pwr_state), POWER_POLL_SLEEP_US, + POWER_OFF_LATENCY_US + POWER_POLL_TIMEOUT_US); + if (ret =3D=3D -ETIMEDOUT) { + dev_err(ctrl->dev, "timed out powering off domain '%s'\n", pd->genpd.nam= e); + return ret; + } + + return regmap_clear_bits(ctrl->base, data->reg_clk_res_ctrl, data->hw_mod= e); +} + +static inline int pxa1908_dsi_power_on(struct generic_pm_domain *genpd) +{ + struct pxa1908_pd *pd =3D to_pxa1908_pd(genpd); + struct pxa1908_pd_ctrl *ctrl =3D pd->ctrl; + + return regmap_set_bits(ctrl->base, APMU_DEBUG, DSI_PHY_DVM_MASK); +} + +static inline int pxa1908_dsi_power_off(struct generic_pm_domain *genpd) +{ + struct pxa1908_pd *pd =3D to_pxa1908_pd(genpd); + struct pxa1908_pd_ctrl *ctrl =3D pd->ctrl; + + return regmap_clear_bits(ctrl->base, APMU_DEBUG, DSI_PHY_DVM_MASK); +} + +#define DOMAIN(_id, _name, ctrl, mode, state) \ + [_id] =3D { \ + .data =3D { \ + .reg_clk_res_ctrl =3D ctrl, \ + .hw_mode =3D BIT(mode), \ + .pwr_state =3D BIT(state), \ + .id =3D _id, \ + }, \ + .genpd =3D { \ + .name =3D _name, \ + .power_on =3D pxa1908_pd_power_on, \ + .power_off =3D pxa1908_pd_power_off, \ + }, \ + } + +static struct pxa1908_pd domains[NR_DOMAINS] =3D { + DOMAIN(PXA1908_POWER_DOMAIN_VPU, "vpu", 0xa4, 19, 2), + DOMAIN(PXA1908_POWER_DOMAIN_GPU, "gpu", 0xcc, 11, 0), + DOMAIN(PXA1908_POWER_DOMAIN_GPU2D, "gpu2d", 0xf4, 11, 6), + DOMAIN(PXA1908_POWER_DOMAIN_ISP, "isp", 0x38, 15, 4), + [PXA1908_POWER_DOMAIN_DSI] =3D { + .genpd =3D { + .name =3D "dsi", + .power_on =3D pxa1908_dsi_power_on, + .power_off =3D pxa1908_dsi_power_off, + /* + * TODO: There is no DSI driver written yet and until then we probably + * don't want to power off the DSI PHY ever. + */ + .flags =3D GENPD_FLAG_ALWAYS_ON, + }, + .data =3D { + /* See above. */ + .keep_on =3D true, + }, + }, +}; + +static void pxa1908_pd_remove(struct auxiliary_device *auxdev) +{ + struct pxa1908_pd *pd; + int ret; + + for (int i =3D NR_DOMAINS - 1; i >=3D 0; i--) { + pd =3D &domains[i]; + + if (!pd->initialized) + continue; + + if (pxa1908_pd_is_on(pd) && !pd->data.keep_on) + pxa1908_pd_power_off(&pd->genpd); + + ret =3D pm_genpd_remove(&pd->genpd); + if (ret) + dev_err(&auxdev->dev, "failed to remove domain '%s': %d\n", + pd->genpd.name, ret); + } +} + +static int +pxa1908_pd_init(struct pxa1908_pd_ctrl *ctrl, int id, struct device *dev) +{ + struct pxa1908_pd *pd =3D &domains[id]; + int ret; + + ctrl->domains[id] =3D &pd->genpd; + + pd->ctrl =3D ctrl; + + /* Make sure the state of the hardware is synced with the domain table ab= ove. */ + if (pd->data.keep_on) { + ret =3D pd->genpd.power_on(&pd->genpd); + if (ret) + return dev_err_probe(dev, ret, "failed to power on domain '%s'\n", + pd->genpd.name); + } else { + if (pxa1908_pd_is_on(pd)) { + dev_warn(dev, + "domain '%s' is on despite being default off; powering off\n", + pd->genpd.name); + + ret =3D pd->genpd.power_off(&pd->genpd); + if (ret) + return dev_err_probe(dev, ret, + "failed to power off domain '%s'\n", + pd->genpd.name); + } + } + + ret =3D pm_genpd_init(&pd->genpd, NULL, !pd->data.keep_on); + if (ret) + return dev_err_probe(dev, ret, "domain '%s' failed to initialize\n", + pd->genpd.name); + + pd->initialized =3D true; + + return 0; +} + +static int +pxa1908_pd_probe(struct auxiliary_device *auxdev, const struct auxiliary_d= evice_id *aux_id) +{ + struct pxa1908_pd_ctrl *ctrl; + struct device *dev =3D &auxdev->dev; + int ret; + + ctrl =3D devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + auxiliary_set_drvdata(auxdev, ctrl); + + ctrl->base =3D syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(ctrl->base)) + return dev_err_probe(dev, PTR_ERR(ctrl->base), "no regmap available\n"); + + ctrl->dev =3D dev; + ctrl->onecell_data.domains =3D ctrl->domains; + ctrl->onecell_data.num_domains =3D NR_DOMAINS; + + for (int i =3D 0; i < NR_DOMAINS; i++) { + ret =3D pxa1908_pd_init(ctrl, i, dev); + if (ret) + goto err; + } + + return of_genpd_add_provider_onecell(dev->parent->of_node, &ctrl->onecell= _data); + +err: + pxa1908_pd_remove(auxdev); + return ret; +} + +static const struct auxiliary_device_id pxa1908_pd_id[] =3D { + { .name =3D "clk_pxa1908_apmu.power" }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, pxa1908_pd_id); + +static struct auxiliary_driver pxa1908_pd_driver =3D { + .probe =3D pxa1908_pd_probe, + .remove =3D pxa1908_pd_remove, + .id_table =3D pxa1908_pd_id, +}; +module_auxiliary_driver(pxa1908_pd_driver); + +MODULE_AUTHOR("Duje Mihanovi=C4=87 "); +MODULE_DESCRIPTION("Marvell PXA1908 power domain driver"); +MODULE_LICENSE("GPL"); --=20 2.51.0