diff options
Diffstat (limited to 'drivers/pinctrl/pinctrl-sunxi.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-sunxi.c | 155 |
1 files changed, 155 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; |