From: Richard Hsu <saraon640529@gmail.com>
To: Richard_Hsu@asmedia.com.tw, Yd_Tseng@asmedia.com.tw,
Jesse1_Chang@asmedia.com.tw, linus.walleij@linaro.org,
bgolaszewski@baylibre.com, bhelgaas@google.com, lkp@intel.com
Cc: kbuild-all@lists.01.org, linux-gpio@vger.kernel.org,
linux-pci@vger.kernel.org, Richard Hsu <saraon640529@gmail.com>
Subject: [PATCH] gpio:asm28xx-18xx: new driver
Date: Thu, 4 Jun 2020 15:32:43 +0800 [thread overview]
Message-ID: <20200604073243.19280-1-saraon640529@gmail.com> (raw)
Hi Linus Walleij,Bartosz Golaszewski and kbuild test robot,
I have fixed the warnings(make W=1 ARCH=i386) by replace two functions
with static type,and resend the patch.
line 69:
<<void pci_config_pm_runtime_get(struct pci_dev *pdev)
>>static void pci_config_pm_runtime_get(struct pci_dev *pdev)
line 91:
<<void pci_config_pm_runtime_put(struct pci_dev *pdev)
>>static void pci_config_pm_runtime_put(struct pci_dev *pdev)
Thanks
BR,
Richard
Signed-off-by: Richard Hsu <saraon640529@gmail.com>
---
drivers/gpio/gpio-asm28xx-18xx.c | 278 +++++++++++++++++++++++++++++++
1 file changed, 278 insertions(+)
create mode 100644 drivers/gpio/gpio-asm28xx-18xx.c
diff --git a/drivers/gpio/gpio-asm28xx-18xx.c b/drivers/gpio/gpio-asm28xx-18xx.c
index 000000000000..0cf8d0df5407
--- /dev/null
+++ b/drivers/gpio/gpio-asm28xx-18xx.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Asmedia 28xx/18xx GPIO driver
+ *
+ * Copyright (C) 2020 ASMedia Technology Inc.
+ * Author: Richard Hsu <Richard_Hsu@asmedia.com.tw>
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/gpio/driver.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+#include <linux/bits.h>
+
+
+/* GPIO registers offsets */
+#define ASM_GPIO_CTRL 0x920
+#define ASM_GPIO_OUTPUT 0x928
+#define ASM_GPIO_INPUT 0x930
+#define ASM_REG_SWITCH 0xFFF
+
+#define ASM_REG_SWITCH_CTL 0x01
+
+#define ASM_GPIO_PIN5 5
+#define ASM_GPIO_DEFAULT 0
+
+
+#define PCI_DEVICE_ID_ASM_28XX_PID1 0x2824
+#define PCI_DEVICE_ID_ASM_28XX_PID2 0x2812
+#define PCI_DEVICE_ID_ASM_28XX_PID3 0x2806
+#define PCI_DEVICE_ID_ASM_18XX_PID1 0x1824
+#define PCI_DEVICE_ID_ASM_18XX_PID2 0x1812
+#define PCI_DEVICE_ID_ASM_18XX_PID3 0x1806
+#define PCI_DEVICE_ID_ASM_81XX_PID1 0x812a
+#define PCI_DEVICE_ID_ASM_81XX_PID2 0x812b
+#define PCI_DEVICE_ID_ASM_80XX_PID1 0x8061
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE. We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static const struct pci_device_id pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, PCI_DEVICE_ID_ASM_28XX_PID1), 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, PCI_DEVICE_ID_ASM_28XX_PID2), 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, PCI_DEVICE_ID_ASM_28XX_PID3), 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, PCI_DEVICE_ID_ASM_18XX_PID1), 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, PCI_DEVICE_ID_ASM_18XX_PID2), 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, PCI_DEVICE_ID_ASM_18XX_PID3), 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, PCI_DEVICE_ID_ASM_81XX_PID1), 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, PCI_DEVICE_ID_ASM_81XX_PID2), 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, PCI_DEVICE_ID_ASM_80XX_PID1), 0 },
+ { 0, }, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+struct asm28xx_gpio {
+ struct gpio_chip chip;
+ struct pci_dev *pdev;
+ spinlock_t lock;
+};
+
+static void pci_config_pm_runtime_get(struct pci_dev *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device *parent = dev->parent;
+
+ if (parent)
+ pm_runtime_get_sync(parent);
+ pm_runtime_get_noresume(dev);
+ /*
+ * pdev->current_state is set to PCI_D3cold during suspending,
+ * so wait until suspending completes
+ */
+ pm_runtime_barrier(dev);
+ /*
+ * Only need to resume devices in D3cold, because config
+ * registers are still accessible for devices suspended but
+ * not in D3cold.
+ */
+ if (pdev->current_state == PCI_D3cold)
+ pm_runtime_resume(dev);
+}
+
+static void pci_config_pm_runtime_put(struct pci_dev *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device *parent = dev->parent;
+
+ pm_runtime_put(dev);
+ if (parent)
+ pm_runtime_put_sync(parent);
+}
+
+static int asm28xx_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ if (offset == ASM_GPIO_PIN5)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void asm28xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct asm28xx_gpio *agp = gpiochip_get_data(chip);
+ u8 temp;
+ unsigned long flags;
+
+ pci_config_pm_runtime_get(agp->pdev);
+ spin_lock_irqsave(&agp->lock, flags);
+ pci_read_config_byte(agp->pdev, ASM_GPIO_OUTPUT, &temp);
+ if (value)
+ temp |= BIT(offset);
+ else
+ temp &= ~BIT(offset);
+
+ pci_write_config_byte(agp->pdev, ASM_GPIO_OUTPUT, temp);
+ spin_unlock_irqrestore(&agp->lock, flags);
+ pci_config_pm_runtime_put(agp->pdev);
+ dev_dbg(chip->parent, "ASMEDIA-28xx/18xx gpio %d set %d reg=%02x\n", offset, value, temp);
+}
+
+static int asm28xx_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct asm28xx_gpio *agp = gpiochip_get_data(chip);
+ u8 temp;
+ unsigned long flags;
+
+ pci_config_pm_runtime_get(agp->pdev);
+ spin_lock_irqsave(&agp->lock, flags);
+ pci_read_config_byte(agp->pdev, ASM_GPIO_INPUT, &temp);
+ spin_unlock_irqrestore(&agp->lock, flags);
+ pci_config_pm_runtime_put(agp->pdev);
+
+ dev_dbg(chip->parent, "ASMEDIA-28xx/18xx GPIO Pin %d get reg=%02x\n", offset, temp);
+ return (temp & BIT(offset)) ? 1 : 0;
+}
+
+static int asm28xx_gpio_dirout(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct asm28xx_gpio *agp = gpiochip_get_data(chip);
+ u8 temp;
+ unsigned long flags;
+
+ pci_config_pm_runtime_get(agp->pdev);
+ spin_lock_irqsave(&agp->lock, flags);
+ pci_read_config_byte(agp->pdev, ASM_GPIO_CTRL, &temp);
+ temp |= BIT(offset);
+ pci_write_config_byte(agp->pdev, ASM_GPIO_CTRL, temp);
+ spin_unlock_irqrestore(&agp->lock, flags);
+ pci_config_pm_runtime_put(agp->pdev);
+ dev_dbg(chip->parent, "ASMEDIA-28xx/18xx dirout gpio %d reg=%02x\n", offset, temp);
+
+ return 0;
+}
+
+static int asm28xx_gpio_dirin(struct gpio_chip *chip, unsigned offset)
+{
+ struct asm28xx_gpio *agp = gpiochip_get_data(chip);
+ u8 temp;
+ unsigned long flags;
+
+ pci_config_pm_runtime_get(agp->pdev);
+ spin_lock_irqsave(&agp->lock, flags);
+ pci_read_config_byte(agp->pdev, ASM_GPIO_CTRL, &temp);
+ temp &= ~BIT(offset);
+ pci_write_config_byte(agp->pdev, ASM_GPIO_CTRL, temp);
+ spin_unlock_irqrestore(&agp->lock, flags);
+ pci_config_pm_runtime_put(agp->pdev);
+ dev_dbg(chip->parent, "ASMEDIA-28xx/18xx dirin gpio %d reg=%02x\n", offset, temp);
+
+ return 0;
+}
+
+static struct asm28xx_gpio gp = {
+ .chip = {
+ .label = "ASM28XX-18XX GPIO",
+ .owner = THIS_MODULE,
+ .ngpio = 8,
+ .request = asm28xx_gpio_request,
+ .set = asm28xx_gpio_set,
+ .get = asm28xx_gpio_get,
+ .direction_output = asm28xx_gpio_dirout,
+ .direction_input = asm28xx_gpio_dirin,
+ },
+};
+
+static int __init asm28xx_gpio_init(void)
+{
+ int err = -ENODEV;
+ struct pci_dev *pdev = NULL;
+ const struct pci_device_id *ent;
+ u8 temp;
+ unsigned long flags;
+ int type;
+
+ /* We look for our device - Asmedia 28XX and 18XX Bridge
+ * I don't know about a system with two such bridges,
+ * so we can assume that there is max. one device.
+ *
+ * We can't use plain pci_driver mechanism,
+ * as the device is really a multiple function device,
+ * main driver that binds to the pci_device is an bus
+ * driver and have to find & bind to the device this way.
+ */
+
+ for_each_pci_dev(pdev) {
+ ent = pci_match_id(pci_tbl, pdev);
+ if (ent) {
+ /* Because GPIO Registers only work on Upstream port. */
+ type = pci_pcie_type(pdev);
+ if (type == PCI_EXP_TYPE_UPSTREAM) {
+ dev_info(&pdev->dev, "ASMEDIA-28xx/18xx Init Upstream detected\n");
+ goto found;
+ }
+ }
+ }
+ goto out;
+
+found:
+ gp.pdev = pdev;
+ gp.chip.parent = &pdev->dev;
+
+ spin_lock_init(&gp.lock);
+
+ err = gpiochip_add_data(&gp.chip, &gp);
+ if (err) {
+ dev_err(&pdev->dev, "GPIO registering failed (%d)\n", err);
+ goto out;
+ }
+
+ pci_config_pm_runtime_get(pdev);
+
+ /* Set PCI_CFG_Switch bit = 1,then we can access GPIO Registers. */
+ spin_lock_irqsave(&gp.lock, flags);
+ pci_read_config_byte(pdev, ASM_REG_SWITCH, &temp);
+ temp |= ASM_REG_SWITCH_CTL;
+ pci_write_config_byte(pdev, ASM_REG_SWITCH, temp);
+ pci_read_config_byte(pdev, ASM_REG_SWITCH, &temp);
+ spin_unlock_irqrestore(&gp.lock, flags);
+
+ pci_config_pm_runtime_put(pdev);
+ dev_err(&pdev->dev, "ASMEDIA-28xx/18xx Init SWITCH = 0x%x\n", temp);
+out:
+ return err;
+}
+
+static void __exit asm28xx_gpio_exit(void)
+{
+ unsigned long flags;
+
+ pci_config_pm_runtime_get(gp.pdev);
+
+ spin_lock_irqsave(&gp.lock, flags);
+ /* Set GPIO Registers to default value. */
+ pci_write_config_byte(gp.pdev, ASM_GPIO_OUTPUT, ASM_GPIO_DEFAULT);
+ pci_write_config_byte(gp.pdev, ASM_GPIO_INPUT, ASM_GPIO_DEFAULT);
+ pci_write_config_byte(gp.pdev, ASM_GPIO_CTRL, ASM_GPIO_DEFAULT);
+ /* Clear PCI_CFG_Switch bit = 0,then we can't access GPIO Registers. */
+ pci_write_config_byte(gp.pdev, ASM_REG_SWITCH, ASM_GPIO_DEFAULT);
+ spin_unlock_irqrestore(&gp.lock, flags);
+ pci_config_pm_runtime_put(gp.pdev);
+
+ gpiochip_remove(&gp.chip);
+}
+
+module_init(asm28xx_gpio_init);
+module_exit(asm28xx_gpio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Richard Hsu <Richard_Hsu@asmedia.com.tw>");
+MODULE_DESCRIPTION("ASMedia 28xx 18xx GPIO Driver");
--
2.17.1
next reply other threads:[~2020-06-04 7:33 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-06-04 7:32 Richard Hsu [this message]
2020-06-04 11:54 ` [PATCH] gpio:asm28xx-18xx: new driver Bartosz Golaszewski
2020-06-04 17:55 ` Bjorn Helgaas
2020-06-05 7:55 ` Bartosz Golaszewski
2020-06-05 10:02 ` Richard Hsu(許育彰)
2020-06-05 10:13 ` Bartosz Golaszewski
-- strict thread matches above, loose matches on Subject: below --
2020-06-01 7:36 Richard Hsu
2020-06-05 17:12 ` Bjorn Helgaas
2020-06-08 8:57 ` Richard Hsu(許育彰)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200604073243.19280-1-saraon640529@gmail.com \
--to=saraon640529@gmail.com \
--cc=Jesse1_Chang@asmedia.com.tw \
--cc=Richard_Hsu@asmedia.com.tw \
--cc=Yd_Tseng@asmedia.com.tw \
--cc=bgolaszewski@baylibre.com \
--cc=bhelgaas@google.com \
--cc=kbuild-all@lists.01.org \
--cc=linus.walleij@linaro.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lkp@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).