Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2219599/?format=api
{ "id": 2219599, "url": "http://patchwork.ozlabs.org/api/patches/2219599/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-pwm/patch/28e29fbfc20c0b8a115d006233c2759d8f49e639.1775223441.git.andrea.porta@suse.com/", "project": { "id": 38, "url": "http://patchwork.ozlabs.org/api/projects/38/?format=api", "name": "Linux PWM development", "link_name": "linux-pwm", "list_id": "linux-pwm.vger.kernel.org", "list_email": "linux-pwm@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<28e29fbfc20c0b8a115d006233c2759d8f49e639.1775223441.git.andrea.porta@suse.com>", "list_archive_url": null, "date": "2026-04-03T14:31:55", "name": "[2/3] pwm: rp1: Add RP1 PWM controller driver", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "a5d9108b54979fafdf296ea0163077eb34be4718", "submitter": { "id": 88172, "url": "http://patchwork.ozlabs.org/api/people/88172/?format=api", "name": "Andrea della Porta", "email": "andrea.porta@suse.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-pwm/patch/28e29fbfc20c0b8a115d006233c2759d8f49e639.1775223441.git.andrea.porta@suse.com/mbox/", "series": [ { "id": 498637, "url": "http://patchwork.ozlabs.org/api/series/498637/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-pwm/list/?series=498637", "date": "2026-04-03T14:31:53", "name": "Add RP1 PWM controller support", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/498637/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2219599/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2219599/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <linux-pwm+bounces-8471-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-pwm@vger.kernel.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=suse.com header.i=@suse.com header.a=rsa-sha256\n header.s=google header.b=BJQS5NNI;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.234.253.10; helo=sea.lore.kernel.org;\n envelope-from=linux-pwm+bounces-8471-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=suse.com header.i=@suse.com\n header.b=\"BJQS5NNI\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.128.50", "smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=suse.com", "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=suse.com" ], "Received": [ "from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fnLpl50SQz1yCt\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 04 Apr 2026 01:34:55 +1100 (AEDT)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 88B923051AB6\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 3 Apr 2026 14:29:05 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 56CD93C5529;\n\tFri, 3 Apr 2026 14:29:03 +0000 (UTC)", "from mail-wm1-f50.google.com (mail-wm1-f50.google.com\n [209.85.128.50])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 4B0D63C4574\n\tfor <linux-pwm@vger.kernel.org>; Fri, 3 Apr 2026 14:29:01 +0000 (UTC)", "by mail-wm1-f50.google.com with SMTP id\n 5b1f17b1804b1-486ff3a0fc1so17964845e9.2\n for <linux-pwm@vger.kernel.org>; Fri, 03 Apr 2026 07:29:01 -0700 (PDT)", "from localhost (host-79-33-140-232.retail.telecomitalia.it.\n [79.33.140.232])\n by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-4888a63c9b1sm141359835e9.5.2026.04.03.07.28.59\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 03 Apr 2026 07:28:59 -0700 (PDT)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1775226543; cv=none;\n b=GLQAgZr2DjBnXkN316zJnd2Rxnps7PMjG2wYyqrFs7JHLeBFgpJLA+HUc4BarRUK+0YchrBurzcWbCjgJkddbHthN+WCgaeoH/4Q5u20TbJnCgsVshCbyJAEEKdKE43cjatenmLkaPsSamjq+R37f5TGk2Qo+OFT9jMRdyy7eHA=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1775226543; c=relaxed/simple;\n\tbh=Qj5E6yHNU8WD4PtmottpXplcpdDze6L6RS98ls6dgwo=;\n\th=From:To:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version:Content-Type;\n b=FWib5VmX9dahdLe0dnqIU/FaRjBXA7ojm5raUUKUQhJbD+gk0yDBXXIAfp24sueOFm28Av3KIR4HNqKNq63BXmi+X6vF6VTUc3vqyJ5t/1MDrNUL/FctAyfcX2j1KDGVv/OIf9555skQHVklWHvWPqCHTAusKeZVWQzcs/5yWAQ=", "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=suse.com;\n spf=pass smtp.mailfrom=suse.com;\n dkim=pass (2048-bit key) header.d=suse.com header.i=@suse.com\n header.b=BJQS5NNI; arc=none smtp.client-ip=209.85.128.50", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=suse.com; s=google; t=1775226540; x=1775831340;\n darn=vger.kernel.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:to:from:from:to:cc:subject:date:message-id\n :reply-to;\n bh=vhZwuIVjB4J+X/P3h/NptU2O5Fjzj5PnlbmODE1JC1Q=;\n b=BJQS5NNIjgWkIh4YcaXnn+4fwhcTsRycIslUUT9JoqegLgBOHRVsqypZ4ADeya2Rah\n VT42QQQfZvD68GK3uKm4unk72iza6iafWoO923vOVdYjuFNDhOv9k2amTJaj2PUEG1lc\n i3MZLfCSdaW/xJO7RJJB/122yEerTIWuZUAyYE46Hk+RdYlDIMynTM1yWSvnSQCsD15c\n BFBwb3qwkbpZ6WYz3O8aQL0/O5poqtWkV7HUb0fktdYa+jZ32rjAKwtLkeZmQ0vpINCm\n rtesO8RVNlPNegKIUxV/UAgmhryIzKNjqdkR18mBUjxHQbs05yQsXjLLQe9z68hSWbqB\n 3aXg==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775226540; x=1775831340;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to\n :cc:subject:date:message-id:reply-to;\n bh=vhZwuIVjB4J+X/P3h/NptU2O5Fjzj5PnlbmODE1JC1Q=;\n b=WbRK4Ffx3Akg9KiPbegrPIFywYJAgrOHGvQ+hV69WZ4HGpJ8tl/WluVA9bImZF6KXC\n X8rlxknSLE9DEWWuy11f7qFCX8DLW6tRM3NViaqHmGru03MprhaQIR+JvqhslibvGGHm\n gW3Y2TP8emV9o7ohLJmXM+nrGxbKMf4tWgcTh41kjA95nywvQ/0X7yI00JSimKADuAgE\n xpj7EWEu0FAFokXxtbyGI7T2prYWRjAW/nVQPlIY+fKPGJ2h3Kto7wnsKeYWBXPvr2K9\n 7kculyHXg6YNK2aoDwQVnatmqFv2k6SNxToTfK7IzJRl4mgvSB/CAVQob3tggF1MY7ZT\n rjKQ==", "X-Forwarded-Encrypted": "i=1;\n AJvYcCUQtS1uXpcv/6nV8OTdLJIlpdPy2Yc0/R8bjxWcq2RsUNQNeMZKrmvs744XbrO/sTLVCvJfPM+gE1M=@vger.kernel.org", "X-Gm-Message-State": "AOJu0Yz+h2riHen5dkNa5ZXrDsI2EgAa+Hbupw8BtZ6g0zCczMSUpe4N\n\tsNtfNiWBego9oynte17OwpBPRBh1cO1S/J+uRN414rB/sUhGPpiykvhyhE5OoyR+2f8=", "X-Gm-Gg": "ATEYQzybntaM4qnuLR/scZyT5GgnotAjMb22uaePgZJZagyKhU2KMeeg4PHWfwAjlt1\n\t5pw4Ca+gM2KJy1BayREqK0zwmI7X59/mHTlX/TODqydkPjN7IMqnWWmRSNtR+bvqAqHQi6/ghZX\n\t51DQ2SmWG0X9s4GEOZUsWpxvWy1/LnJyHLpOf7sTMUfdNwCfztetWfM2WN/ktKCatMZtUFfefuL\n\tzl6MDqwbg310cpBppgY4XcvoVD5AgFK7EC6KtpuZ562sgEimWCppbSCqbnGZ7cxegPQw1iONcJe\n\tEOLzknxCk2lWdzlz135Lvse24oo7UdjxXbMCX8mM+m/9tx0J1/+7O2rFeaI34rLEuq77sv8b00T\n\t5wf7kDe1/T74An7QBLG6SERYlp/gtu4Mt4GbWKMTEdN1rPTLhbNst2A7FXNhvIA3SknqqHS9fmX\n\t7ruxTdN+QCp65r6k7HyH0GIcViiDA1rwArEc9VsA1AqsQZLJVHAWM8qbUPdOyzTcgcmFek2X+nv\n\tjwZQ4M=", "X-Received": "by 2002:a05:600c:4e86:b0:480:4a8f:2d5c with SMTP id\n 5b1f17b1804b1-488997c9b69mr47679745e9.29.1775226539544;\n Fri, 03 Apr 2026 07:28:59 -0700 (PDT)", "From": "Andrea della Porta <andrea.porta@suse.com>", "To": "=?utf-8?q?Uwe_Kleine-K=C3=B6nig?= <ukleinek@kernel.org>,\n linux-pwm@vger.kernel.org, Rob Herring <robh@kernel.org>,\n Krzysztof Kozlowski <krzk+dt@kernel.org>, Conor Dooley <conor+dt@kernel.org>,\n Florian Fainelli <florian.fainelli@broadcom.com>,\n Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>,\n Andrea della Porta <andrea.porta@suse.com>, devicetree@vger.kernel.org,\n linux-rpi-kernel@lists.infradead.org, linux-arm-kernel@lists.infradead.org,\n linux-kernel@vger.kernel.org, Naushir Patuck <naush@raspberrypi.com>,\n Stanimir Varbanov <svarbanov@suse.de>", "Subject": "[PATCH 2/3] pwm: rp1: Add RP1 PWM controller driver", "Date": "Fri, 3 Apr 2026 16:31:55 +0200", "Message-ID": "\n <28e29fbfc20c0b8a115d006233c2759d8f49e639.1775223441.git.andrea.porta@suse.com>", "X-Mailer": "git-send-email 2.51.0", "In-Reply-To": "<cover.1775223441.git.andrea.porta@suse.com>", "References": "<cover.1775223441.git.andrea.porta@suse.com>", "Precedence": "bulk", "X-Mailing-List": "linux-pwm@vger.kernel.org", "List-Id": "<linux-pwm.vger.kernel.org>", "List-Subscribe": "<mailto:linux-pwm+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-pwm+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit" }, "content": "From: Naushir Patuck <naush@raspberrypi.com>\n\nThe Raspberry Pi RP1 southbridge features an embedded PWM\ncontroller with 4 output channels, alongside an RPM interface\nto read the fan speed on the Raspberry Pi 5.\n\nAdd the supporting driver.\n\nSigned-off-by: Naushir Patuck <naush@raspberrypi.com>\nCo-developed-by: Stanimir Varbanov <svarbanov@suse.de>\nSigned-off-by: Stanimir Varbanov <svarbanov@suse.de>\nSigned-off-by: Andrea della Porta <andrea.porta@suse.com>\n---\n drivers/pwm/Kconfig | 10 ++\n drivers/pwm/Makefile | 1 +\n drivers/pwm/pwm-rp1.c | 244 ++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 255 insertions(+)\n create mode 100644 drivers/pwm/pwm-rp1.c", "diff": "diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig\nindex 6f3147518376a..22e4fc6385da2 100644\n--- a/drivers/pwm/Kconfig\n+++ b/drivers/pwm/Kconfig\n@@ -625,6 +625,16 @@ config PWM_ROCKCHIP\n \t Generic PWM framework driver for the PWM controller found on\n \t Rockchip SoCs.\n \n+config PWM_RP1\n+\ttristate \"RP1 PWM support\"\n+\tdepends on MISC_RP1 || COMPILE_TEST\n+\tdepends on HWMON\n+\thelp\n+\t PWM framework driver for Raspberry Pi RP1 controller\n+\n+\t To compile this driver as a module, choose M here: the module\n+\t will be called pwm-rp1.\n+\n config PWM_SAMSUNG\n \ttristate \"Samsung PWM support\"\n \tdepends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST\ndiff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile\nindex 0dc0d2b69025d..895a7c42fe9c0 100644\n--- a/drivers/pwm/Makefile\n+++ b/drivers/pwm/Makefile\n@@ -56,6 +56,7 @@ obj-$(CONFIG_PWM_RENESAS_RZG2L_GPT)\t+= pwm-rzg2l-gpt.o\n obj-$(CONFIG_PWM_RENESAS_RZ_MTU3)\t+= pwm-rz-mtu3.o\n obj-$(CONFIG_PWM_RENESAS_TPU)\t+= pwm-renesas-tpu.o\n obj-$(CONFIG_PWM_ROCKCHIP)\t+= pwm-rockchip.o\n+obj-$(CONFIG_PWM_RP1)\t\t+= pwm-rp1.o\n obj-$(CONFIG_PWM_SAMSUNG)\t+= pwm-samsung.o\n obj-$(CONFIG_PWM_SIFIVE)\t+= pwm-sifive.o\n obj-$(CONFIG_PWM_SL28CPLD)\t+= pwm-sl28cpld.o\ndiff --git a/drivers/pwm/pwm-rp1.c b/drivers/pwm/pwm-rp1.c\nnew file mode 100644\nindex 0000000000000..0a1c1c1dd27e9\n--- /dev/null\n+++ b/drivers/pwm/pwm-rp1.c\n@@ -0,0 +1,244 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * pwm-rp1.c\n+ *\n+ * Raspberry Pi RP1 PWM.\n+ *\n+ * Copyright © 2026 Raspberry Pi Ltd.\n+ *\n+ * Author: Naushir Patuck (naush@raspberrypi.com)\n+ *\n+ * Based on the pwm-bcm2835 driver by:\n+ * Bart Tanghe <bart.tanghe@thomasmore.be>\n+ */\n+\n+#include <linux/bitops.h>\n+#include <linux/clk.h>\n+#include <linux/err.h>\n+#include <linux/hwmon.h>\n+#include <linux/io.h>\n+#include <linux/module.h>\n+#include <linux/of.h>\n+#include <linux/platform_device.h>\n+#include <linux/pwm.h>\n+\n+#define PWM_GLOBAL_CTRL\t\t0x000\n+#define PWM_CHANNEL_CTRL(x)\t(0x014 + ((x) * 0x10))\n+#define PWM_RANGE(x)\t\t(0x018 + ((x) * 0x10))\n+#define PWM_PHASE(x)\t\t(0x01C + ((x) * 0x10))\n+#define PWM_DUTY(x)\t\t(0x020 + ((x) * 0x10))\n+\n+/* 8:FIFO_POP_MASK + 0:Trailing edge M/S modulation */\n+#define PWM_CHANNEL_DEFAULT\t(BIT(8) + BIT(0))\n+#define PWM_CHANNEL_ENABLE(x)\tBIT(x)\n+#define PWM_POLARITY\t\tBIT(3)\n+#define SET_UPDATE\t\tBIT(31)\n+#define PWM_MODE_MASK\t\tGENMASK(1, 0)\n+\n+#define NUM_PWMS\t\t4\n+\n+struct rp1_pwm {\n+\tvoid __iomem\t*base;\n+\tstruct clk\t*clk;\n+};\n+\n+static const struct hwmon_channel_info * const rp1_fan_hwmon_info[] = {\n+\tHWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),\n+\tNULL\n+};\n+\n+static umode_t rp1_fan_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,\n+\t\t\t\t\tu32 attr, int channel)\n+{\n+\tumode_t mode = 0;\n+\n+\tif (type == hwmon_fan && attr == hwmon_fan_input)\n+\t\tmode = 0444;\n+\n+\treturn mode;\n+}\n+\n+static int rp1_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type,\n+\t\t\t u32 attr, int channel, long *val)\n+{\n+\tstruct rp1_pwm *rp1 = dev_get_drvdata(dev);\n+\n+\tif (type != hwmon_fan || attr != hwmon_fan_input)\n+\t\treturn -EOPNOTSUPP;\n+\n+\t*val = readl(rp1->base + PWM_PHASE(2));\n+\n+\treturn 0;\n+}\n+\n+static const struct hwmon_ops rp1_fan_hwmon_ops = {\n+\t.is_visible = rp1_fan_hwmon_is_visible,\n+\t.read = rp1_fan_hwmon_read,\n+};\n+\n+static const struct hwmon_chip_info rp1_fan_hwmon_chip_info = {\n+\t.ops = &rp1_fan_hwmon_ops,\n+\t.info = rp1_fan_hwmon_info,\n+};\n+\n+static void rp1_pwm_apply_config(struct pwm_chip *chip, struct pwm_device *pwm)\n+{\n+\tstruct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);\n+\tu32 value;\n+\n+\tvalue = readl(rp1->base + PWM_GLOBAL_CTRL);\n+\tvalue |= SET_UPDATE;\n+\twritel(value, rp1->base + PWM_GLOBAL_CTRL);\n+}\n+\n+static int rp1_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)\n+{\n+\tstruct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);\n+\n+\twritel(PWM_CHANNEL_DEFAULT, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));\n+\treturn 0;\n+}\n+\n+static void rp1_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)\n+{\n+\tstruct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);\n+\tu32 value;\n+\n+\tvalue = readl(rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));\n+\tvalue &= ~PWM_MODE_MASK;\n+\twritel(value, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));\n+\n+\trp1_pwm_apply_config(chip, pwm);\n+}\n+\n+static int rp1_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,\n+\t\t\t const struct pwm_state *state)\n+{\n+\tstruct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);\n+\tunsigned long clk_rate = clk_get_rate(rp1->clk);\n+\tunsigned long clk_period;\n+\tu32 value;\n+\n+\tif (!clk_rate) {\n+\t\tdev_err(&chip->dev, \"failed to get clock rate\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* set period and duty cycle */\n+\tclk_period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, clk_rate);\n+\n+\twritel(DIV_ROUND_CLOSEST(state->duty_cycle, clk_period),\n+\t rp1->base + PWM_DUTY(pwm->hwpwm));\n+\n+\twritel(DIV_ROUND_CLOSEST(state->period, clk_period),\n+\t rp1->base + PWM_RANGE(pwm->hwpwm));\n+\n+\t/* set polarity */\n+\tvalue = readl(rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));\n+\tif (state->polarity == PWM_POLARITY_NORMAL)\n+\t\tvalue &= ~PWM_POLARITY;\n+\telse\n+\t\tvalue |= PWM_POLARITY;\n+\twritel(value, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));\n+\n+\t/* enable/disable */\n+\tvalue = readl(rp1->base + PWM_GLOBAL_CTRL);\n+\tif (state->enabled)\n+\t\tvalue |= PWM_CHANNEL_ENABLE(pwm->hwpwm);\n+\telse\n+\t\tvalue &= ~PWM_CHANNEL_ENABLE(pwm->hwpwm);\n+\twritel(value, rp1->base + PWM_GLOBAL_CTRL);\n+\n+\trp1_pwm_apply_config(chip, pwm);\n+\n+\treturn 0;\n+}\n+\n+static const struct pwm_ops rp1_pwm_ops = {\n+\t.request = rp1_pwm_request,\n+\t.free = rp1_pwm_free,\n+\t.apply = rp1_pwm_apply,\n+};\n+\n+static int rp1_pwm_probe(struct platform_device *pdev)\n+{\n+\tstruct device *dev = &pdev->dev;\n+\tstruct device *hwmon_dev;\n+\tstruct pwm_chip *chip;\n+\tstruct rp1_pwm *rp1;\n+\tint ret;\n+\n+\tchip = devm_pwmchip_alloc(dev, NUM_PWMS, sizeof(*rp1));\n+\tif (IS_ERR(chip))\n+\t\treturn PTR_ERR(chip);\n+\n+\trp1 = pwmchip_get_drvdata(chip);\n+\n+\trp1->base = devm_platform_ioremap_resource(pdev, 0);\n+\tif (IS_ERR(rp1->base))\n+\t\treturn PTR_ERR(rp1->base);\n+\n+\trp1->clk = devm_clk_get_enabled(dev, NULL);\n+\tif (IS_ERR(rp1->clk))\n+\t\treturn dev_err_probe(dev, PTR_ERR(rp1->clk), \"clock not found\\n\");\n+\n+\tret = devm_clk_rate_exclusive_get(dev, rp1->clk);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret, \"fail to get exclusive rate\\n\");\n+\n+\tchip->ops = &rp1_pwm_ops;\n+\n+\tplatform_set_drvdata(pdev, chip);\n+\n+\tret = devm_pwmchip_add(dev, chip);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret, \"failed to register PWM chip\\n\");\n+\n+\thwmon_dev = devm_hwmon_device_register_with_info(dev, \"rp1_fan_tach\", rp1,\n+\t\t\t\t\t\t\t &rp1_fan_hwmon_chip_info,\n+\t\t\t\t\t\t\t NULL);\n+\n+\tif (IS_ERR(hwmon_dev))\n+\t\treturn dev_err_probe(dev, PTR_ERR(hwmon_dev),\n+\t\t\t\t \"failed to register hwmon fan device\\n\");\n+\n+\treturn 0;\n+}\n+\n+static int rp1_pwm_suspend(struct device *dev)\n+{\n+\tstruct rp1_pwm *rp1 = dev_get_drvdata(dev);\n+\n+\tclk_disable_unprepare(rp1->clk);\n+\n+\treturn 0;\n+}\n+\n+static int rp1_pwm_resume(struct device *dev)\n+{\n+\tstruct rp1_pwm *rp1 = dev_get_drvdata(dev);\n+\n+\treturn clk_prepare_enable(rp1->clk);\n+}\n+\n+static DEFINE_SIMPLE_DEV_PM_OPS(rp1_pwm_pm_ops, rp1_pwm_suspend, rp1_pwm_resume);\n+\n+static const struct of_device_id rp1_pwm_of_match[] = {\n+\t{ .compatible = \"raspberrypi,rp1-pwm\" },\n+\t{ /* sentinel */ }\n+};\n+MODULE_DEVICE_TABLE(of, rp1_pwm_of_match);\n+\n+static struct platform_driver rp1_pwm_driver = {\n+\t.probe = rp1_pwm_probe,\n+\t.driver = {\n+\t\t.name = \"rp1-pwm\",\n+\t\t.of_match_table = rp1_pwm_of_match,\n+\t\t.pm = pm_ptr(&rp1_pwm_pm_ops),\n+\t},\n+};\n+module_platform_driver(rp1_pwm_driver);\n+\n+MODULE_DESCRIPTION(\"RP1 PWM driver\");\n+MODULE_AUTHOR(\"Naushir Patuck <naush@raspberrypi.com>\");\n+MODULE_LICENSE(\"GPL\");\n", "prefixes": [ "2/3" ] }