diff options
-rw-r--r-- | drivers/pinctrl/pinctrl-sunxi.c | 155 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-sunxi.h | 68 |
2 files changed, 223 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c index f4a74f1c0bfd..e2bab0f75fc5 100644 --- a/drivers/pinctrl/pinctrl-sunxi.c +++ b/drivers/pinctrl/pinctrl-sunxi.c | |||
@@ -13,10 +13,12 @@ | |||
13 | #include <linux/io.h> | 13 | #include <linux/io.h> |
14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
15 | #include <linux/gpio.h> | 15 | #include <linux/gpio.h> |
16 | #include <linux/irqdomain.h> | ||
16 | #include <linux/module.h> | 17 | #include <linux/module.h> |
17 | #include <linux/of.h> | 18 | #include <linux/of.h> |
18 | #include <linux/of_address.h> | 19 | #include <linux/of_address.h> |
19 | #include <linux/of_device.h> | 20 | #include <linux/of_device.h> |
21 | #include <linux/of_irq.h> | ||
20 | #include <linux/pinctrl/consumer.h> | 22 | #include <linux/pinctrl/consumer.h> |
21 | #include <linux/pinctrl/machine.h> | 23 | #include <linux/pinctrl/machine.h> |
22 | #include <linux/pinctrl/pinctrl.h> | 24 | #include <linux/pinctrl/pinctrl.h> |
@@ -1796,6 +1798,26 @@ static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc, | |||
1796 | return pin; | 1798 | return pin; |
1797 | } | 1799 | } |
1798 | 1800 | ||
1801 | static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
1802 | { | ||
1803 | struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev); | ||
1804 | struct sunxi_desc_function *desc; | ||
1805 | |||
1806 | if (offset > chip->ngpio) | ||
1807 | return -ENXIO; | ||
1808 | |||
1809 | desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, "irq"); | ||
1810 | if (!desc) | ||
1811 | return -EINVAL; | ||
1812 | |||
1813 | pctl->irq_array[desc->irqnum] = offset; | ||
1814 | |||
1815 | dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n", | ||
1816 | chip->label, offset + chip->base, desc->irqnum); | ||
1817 | |||
1818 | return irq_find_mapping(pctl->domain, desc->irqnum); | ||
1819 | } | ||
1820 | |||
1799 | static struct gpio_chip sunxi_pinctrl_gpio_chip = { | 1821 | static struct gpio_chip sunxi_pinctrl_gpio_chip = { |
1800 | .owner = THIS_MODULE, | 1822 | .owner = THIS_MODULE, |
1801 | .request = sunxi_pinctrl_gpio_request, | 1823 | .request = sunxi_pinctrl_gpio_request, |
@@ -1805,10 +1827,118 @@ static struct gpio_chip sunxi_pinctrl_gpio_chip = { | |||
1805 | .get = sunxi_pinctrl_gpio_get, | 1827 | .get = sunxi_pinctrl_gpio_get, |
1806 | .set = sunxi_pinctrl_gpio_set, | 1828 | .set = sunxi_pinctrl_gpio_set, |
1807 | .of_xlate = sunxi_pinctrl_gpio_of_xlate, | 1829 | .of_xlate = sunxi_pinctrl_gpio_of_xlate, |
1830 | .to_irq = sunxi_pinctrl_gpio_to_irq, | ||
1808 | .of_gpio_n_cells = 3, | 1831 | .of_gpio_n_cells = 3, |
1809 | .can_sleep = 0, | 1832 | .can_sleep = 0, |
1810 | }; | 1833 | }; |
1811 | 1834 | ||
1835 | static int sunxi_pinctrl_irq_set_type(struct irq_data *d, | ||
1836 | unsigned int type) | ||
1837 | { | ||
1838 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | ||
1839 | u32 reg = sunxi_irq_cfg_reg(d->hwirq); | ||
1840 | u8 index = sunxi_irq_cfg_offset(d->hwirq); | ||
1841 | u8 mode; | ||
1842 | |||
1843 | switch (type) { | ||
1844 | case IRQ_TYPE_EDGE_RISING: | ||
1845 | mode = IRQ_EDGE_RISING; | ||
1846 | break; | ||
1847 | case IRQ_TYPE_EDGE_FALLING: | ||
1848 | mode = IRQ_EDGE_FALLING; | ||
1849 | break; | ||
1850 | case IRQ_TYPE_EDGE_BOTH: | ||
1851 | mode = IRQ_EDGE_BOTH; | ||
1852 | break; | ||
1853 | case IRQ_TYPE_LEVEL_HIGH: | ||
1854 | mode = IRQ_LEVEL_HIGH; | ||
1855 | break; | ||
1856 | case IRQ_TYPE_LEVEL_LOW: | ||
1857 | mode = IRQ_LEVEL_LOW; | ||
1858 | break; | ||
1859 | default: | ||
1860 | return -EINVAL; | ||
1861 | } | ||
1862 | |||
1863 | writel((mode & IRQ_CFG_IRQ_MASK) << index, pctl->membase + reg); | ||
1864 | |||
1865 | return 0; | ||
1866 | } | ||
1867 | |||
1868 | static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d) | ||
1869 | { | ||
1870 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | ||
1871 | u32 ctrl_reg = sunxi_irq_ctrl_reg(d->hwirq); | ||
1872 | u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq); | ||
1873 | u32 status_reg = sunxi_irq_status_reg(d->hwirq); | ||
1874 | u8 status_idx = sunxi_irq_status_offset(d->hwirq); | ||
1875 | u32 val; | ||
1876 | |||
1877 | /* Mask the IRQ */ | ||
1878 | val = readl(pctl->membase + ctrl_reg); | ||
1879 | writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg); | ||
1880 | |||
1881 | /* Clear the IRQ */ | ||
1882 | writel(1 << status_idx, pctl->membase + status_reg); | ||
1883 | } | ||
1884 | |||
1885 | static void sunxi_pinctrl_irq_mask(struct irq_data *d) | ||
1886 | { | ||
1887 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | ||
1888 | u32 reg = sunxi_irq_ctrl_reg(d->hwirq); | ||
1889 | u8 idx = sunxi_irq_ctrl_offset(d->hwirq); | ||
1890 | u32 val; | ||
1891 | |||
1892 | /* Mask the IRQ */ | ||
1893 | val = readl(pctl->membase + reg); | ||
1894 | writel(val & ~(1 << idx), pctl->membase + reg); | ||
1895 | } | ||
1896 | |||
1897 | static void sunxi_pinctrl_irq_unmask(struct irq_data *d) | ||
1898 | { | ||
1899 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | ||
1900 | struct sunxi_desc_function *func; | ||
1901 | u32 reg = sunxi_irq_ctrl_reg(d->hwirq); | ||
1902 | u8 idx = sunxi_irq_ctrl_offset(d->hwirq); | ||
1903 | u32 val; | ||
1904 | |||
1905 | func = sunxi_pinctrl_desc_find_function_by_pin(pctl, | ||
1906 | pctl->irq_array[d->hwirq], | ||
1907 | "irq"); | ||
1908 | |||
1909 | /* Change muxing to INT mode */ | ||
1910 | sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval); | ||
1911 | |||
1912 | /* Unmask the IRQ */ | ||
1913 | val = readl(pctl->membase + reg); | ||
1914 | writel(val | (1 << idx), pctl->membase + reg); | ||
1915 | } | ||
1916 | |||
1917 | static struct irq_chip sunxi_pinctrl_irq_chip = { | ||
1918 | .irq_mask = sunxi_pinctrl_irq_mask, | ||
1919 | .irq_mask_ack = sunxi_pinctrl_irq_mask_ack, | ||
1920 | .irq_unmask = sunxi_pinctrl_irq_unmask, | ||
1921 | .irq_set_type = sunxi_pinctrl_irq_set_type, | ||
1922 | }; | ||
1923 | |||
1924 | static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc) | ||
1925 | { | ||
1926 | struct sunxi_pinctrl *pctl = irq_get_handler_data(irq); | ||
1927 | const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG); | ||
1928 | |||
1929 | /* Clear all interrupts */ | ||
1930 | writel(reg, pctl->membase + IRQ_STATUS_REG); | ||
1931 | |||
1932 | if (reg) { | ||
1933 | int irqoffset; | ||
1934 | |||
1935 | for_each_set_bit(irqoffset, ®, SUNXI_IRQ_NUMBER) { | ||
1936 | int pin_irq = irq_find_mapping(pctl->domain, irqoffset); | ||
1937 | generic_handle_irq(pin_irq); | ||
1938 | } | ||
1939 | } | ||
1940 | } | ||
1941 | |||
1812 | static struct of_device_id sunxi_pinctrl_match[] = { | 1942 | static struct of_device_id sunxi_pinctrl_match[] = { |
1813 | { .compatible = "allwinner,sun4i-a10-pinctrl", .data = (void *)&sun4i_a10_pinctrl_data }, | 1943 | { .compatible = "allwinner,sun4i-a10-pinctrl", .data = (void *)&sun4i_a10_pinctrl_data }, |
1814 | { .compatible = "allwinner,sun5i-a13-pinctrl", .data = (void *)&sun5i_a13_pinctrl_data }, | 1944 | { .compatible = "allwinner,sun5i-a13-pinctrl", .data = (void *)&sun5i_a13_pinctrl_data }, |
@@ -2005,6 +2135,31 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) | |||
2005 | 2135 | ||
2006 | clk_prepare_enable(clk); | 2136 | clk_prepare_enable(clk); |
2007 | 2137 | ||
2138 | pctl->irq = irq_of_parse_and_map(node, 0); | ||
2139 | if (!pctl->irq) { | ||
2140 | ret = -EINVAL; | ||
2141 | goto gpiochip_error; | ||
2142 | } | ||
2143 | |||
2144 | pctl->domain = irq_domain_add_linear(node, SUNXI_IRQ_NUMBER, | ||
2145 | &irq_domain_simple_ops, NULL); | ||
2146 | if (!pctl->domain) { | ||
2147 | dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); | ||
2148 | ret = -ENOMEM; | ||
2149 | goto gpiochip_error; | ||
2150 | } | ||
2151 | |||
2152 | for (i = 0; i < SUNXI_IRQ_NUMBER; i++) { | ||
2153 | int irqno = irq_create_mapping(pctl->domain, i); | ||
2154 | |||
2155 | irq_set_chip_and_handler(irqno, &sunxi_pinctrl_irq_chip, | ||
2156 | handle_simple_irq); | ||
2157 | irq_set_chip_data(irqno, pctl); | ||
2158 | }; | ||
2159 | |||
2160 | irq_set_chained_handler(pctl->irq, sunxi_pinctrl_irq_handler); | ||
2161 | irq_set_handler_data(pctl->irq, pctl); | ||
2162 | |||
2008 | dev_info(&pdev->dev, "initialized sunXi PIO driver\n"); | 2163 | dev_info(&pdev->dev, "initialized sunXi PIO driver\n"); |
2009 | 2164 | ||
2010 | return 0; | 2165 | return 0; |
diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h index e921621059ce..d68047d8f699 100644 --- a/drivers/pinctrl/pinctrl-sunxi.h +++ b/drivers/pinctrl/pinctrl-sunxi.h | |||
@@ -344,9 +344,31 @@ | |||
344 | #define PULL_PINS_BITS 2 | 344 | #define PULL_PINS_BITS 2 |
345 | #define PULL_PINS_MASK 0x03 | 345 | #define PULL_PINS_MASK 0x03 |
346 | 346 | ||
347 | #define SUNXI_IRQ_NUMBER 32 | ||
348 | |||
349 | #define IRQ_CFG_REG 0x200 | ||
350 | #define IRQ_CFG_IRQ_PER_REG 8 | ||
351 | #define IRQ_CFG_IRQ_BITS 4 | ||
352 | #define IRQ_CFG_IRQ_MASK ((1 << IRQ_CFG_IRQ_BITS) - 1) | ||
353 | #define IRQ_CTRL_REG 0x210 | ||
354 | #define IRQ_CTRL_IRQ_PER_REG 32 | ||
355 | #define IRQ_CTRL_IRQ_BITS 1 | ||
356 | #define IRQ_CTRL_IRQ_MASK ((1 << IRQ_CTRL_IRQ_BITS) - 1) | ||
357 | #define IRQ_STATUS_REG 0x214 | ||
358 | #define IRQ_STATUS_IRQ_PER_REG 32 | ||
359 | #define IRQ_STATUS_IRQ_BITS 1 | ||
360 | #define IRQ_STATUS_IRQ_MASK ((1 << IRQ_STATUS_IRQ_BITS) - 1) | ||
361 | |||
362 | #define IRQ_EDGE_RISING 0x00 | ||
363 | #define IRQ_EDGE_FALLING 0x01 | ||
364 | #define IRQ_LEVEL_HIGH 0x02 | ||
365 | #define IRQ_LEVEL_LOW 0x03 | ||
366 | #define IRQ_EDGE_BOTH 0x04 | ||
367 | |||
347 | struct sunxi_desc_function { | 368 | struct sunxi_desc_function { |
348 | const char *name; | 369 | const char *name; |
349 | u8 muxval; | 370 | u8 muxval; |
371 | u8 irqnum; | ||
350 | }; | 372 | }; |
351 | 373 | ||
352 | struct sunxi_desc_pin { | 374 | struct sunxi_desc_pin { |
@@ -378,10 +400,13 @@ struct sunxi_pinctrl { | |||
378 | struct gpio_chip *chip; | 400 | struct gpio_chip *chip; |
379 | struct sunxi_pinctrl_desc *desc; | 401 | struct sunxi_pinctrl_desc *desc; |
380 | struct device *dev; | 402 | struct device *dev; |
403 | struct irq_domain *domain; | ||
381 | struct sunxi_pinctrl_function *functions; | 404 | struct sunxi_pinctrl_function *functions; |
382 | unsigned nfunctions; | 405 | unsigned nfunctions; |
383 | struct sunxi_pinctrl_group *groups; | 406 | struct sunxi_pinctrl_group *groups; |
384 | unsigned ngroups; | 407 | unsigned ngroups; |
408 | int irq; | ||
409 | int irq_array[SUNXI_IRQ_NUMBER]; | ||
385 | struct pinctrl_dev *pctl_dev; | 410 | struct pinctrl_dev *pctl_dev; |
386 | }; | 411 | }; |
387 | 412 | ||
@@ -398,6 +423,13 @@ struct sunxi_pinctrl { | |||
398 | .muxval = _val, \ | 423 | .muxval = _val, \ |
399 | } | 424 | } |
400 | 425 | ||
426 | #define SUNXI_FUNCTION_IRQ(_val, _irq) \ | ||
427 | { \ | ||
428 | .name = "irq", \ | ||
429 | .muxval = _val, \ | ||
430 | .irqnum = _irq, \ | ||
431 | } | ||
432 | |||
401 | /* | 433 | /* |
402 | * The sunXi PIO registers are organized as is: | 434 | * The sunXi PIO registers are organized as is: |
403 | * 0x00 - 0x0c Muxing values. | 435 | * 0x00 - 0x0c Muxing values. |
@@ -475,4 +507,40 @@ static inline u32 sunxi_pull_offset(u16 pin) | |||
475 | return pin_num * PULL_PINS_BITS; | 507 | return pin_num * PULL_PINS_BITS; |
476 | } | 508 | } |
477 | 509 | ||
510 | static inline u32 sunxi_irq_cfg_reg(u16 irq) | ||
511 | { | ||
512 | u8 reg = irq / IRQ_CFG_IRQ_PER_REG; | ||
513 | return reg + IRQ_CFG_REG; | ||
514 | } | ||
515 | |||
516 | static inline u32 sunxi_irq_cfg_offset(u16 irq) | ||
517 | { | ||
518 | u32 irq_num = irq % IRQ_CFG_IRQ_PER_REG; | ||
519 | return irq_num * IRQ_CFG_IRQ_BITS; | ||
520 | } | ||
521 | |||
522 | static inline u32 sunxi_irq_ctrl_reg(u16 irq) | ||
523 | { | ||
524 | u8 reg = irq / IRQ_CTRL_IRQ_PER_REG; | ||
525 | return reg + IRQ_CTRL_REG; | ||
526 | } | ||
527 | |||
528 | static inline u32 sunxi_irq_ctrl_offset(u16 irq) | ||
529 | { | ||
530 | u32 irq_num = irq % IRQ_CTRL_IRQ_PER_REG; | ||
531 | return irq_num * IRQ_CTRL_IRQ_BITS; | ||
532 | } | ||
533 | |||
534 | static inline u32 sunxi_irq_status_reg(u16 irq) | ||
535 | { | ||
536 | u8 reg = irq / IRQ_STATUS_IRQ_PER_REG; | ||
537 | return reg + IRQ_STATUS_REG; | ||
538 | } | ||
539 | |||
540 | static inline u32 sunxi_irq_status_offset(u16 irq) | ||
541 | { | ||
542 | u32 irq_num = irq % IRQ_STATUS_IRQ_PER_REG; | ||
543 | return irq_num * IRQ_STATUS_IRQ_BITS; | ||
544 | } | ||
545 | |||
478 | #endif /* __PINCTRL_SUNXI_H */ | 546 | #endif /* __PINCTRL_SUNXI_H */ |