diff options
Diffstat (limited to 'drivers/pinctrl/pinctrl-tz1090.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-tz1090.c | 140 |
1 files changed, 80 insertions, 60 deletions
diff --git a/drivers/pinctrl/pinctrl-tz1090.c b/drivers/pinctrl/pinctrl-tz1090.c index 72d955252e41..bc9cd7a7602e 100644 --- a/drivers/pinctrl/pinctrl-tz1090.c +++ b/drivers/pinctrl/pinctrl-tz1090.c | |||
@@ -1762,39 +1762,46 @@ static int tz1090_pinconf_get(struct pinctrl_dev *pctldev, | |||
1762 | } | 1762 | } |
1763 | 1763 | ||
1764 | static int tz1090_pinconf_set(struct pinctrl_dev *pctldev, | 1764 | static int tz1090_pinconf_set(struct pinctrl_dev *pctldev, |
1765 | unsigned int pin, unsigned long config) | 1765 | unsigned int pin, unsigned long *configs, |
1766 | unsigned num_configs) | ||
1766 | { | 1767 | { |
1767 | struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | 1768 | struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); |
1768 | enum pin_config_param param = pinconf_to_config_param(config); | 1769 | enum pin_config_param param; |
1769 | unsigned int arg = pinconf_to_config_argument(config); | 1770 | unsigned int arg; |
1770 | int ret; | 1771 | int ret; |
1771 | u32 reg, width, mask, shift, val, tmp; | 1772 | u32 reg, width, mask, shift, val, tmp; |
1772 | unsigned long flags; | 1773 | unsigned long flags; |
1774 | int i; | ||
1773 | 1775 | ||
1774 | dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n", | 1776 | for (i = 0; i < num_configs; i++) { |
1775 | __func__, tz1090_pins[pin].name, config); | 1777 | param = pinconf_to_config_param(configs[i]); |
1778 | arg = pinconf_to_config_argument(configs[i]); | ||
1776 | 1779 | ||
1777 | /* Get register information */ | 1780 | dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n", |
1778 | ret = tz1090_pinconf_reg(pctldev, pin, param, true, | 1781 | __func__, tz1090_pins[pin].name, configs[i]); |
1779 | ®, &width, &mask, &shift, &val); | ||
1780 | if (ret < 0) | ||
1781 | return ret; | ||
1782 | 1782 | ||
1783 | /* Unpack argument and range check it */ | 1783 | /* Get register information */ |
1784 | if (arg > 1) { | 1784 | ret = tz1090_pinconf_reg(pctldev, pin, param, true, |
1785 | dev_dbg(pctldev->dev, "%s: arg %u out of range\n", | 1785 | ®, &width, &mask, &shift, &val); |
1786 | __func__, arg); | 1786 | if (ret < 0) |
1787 | return -EINVAL; | 1787 | return ret; |
1788 | } | ||
1789 | 1788 | ||
1790 | /* Write register field */ | 1789 | /* Unpack argument and range check it */ |
1791 | __global_lock2(flags); | 1790 | if (arg > 1) { |
1792 | tmp = pmx_read(pmx, reg); | 1791 | dev_dbg(pctldev->dev, "%s: arg %u out of range\n", |
1793 | tmp &= ~mask; | 1792 | __func__, arg); |
1794 | if (arg) | 1793 | return -EINVAL; |
1795 | tmp |= val << shift; | 1794 | } |
1796 | pmx_write(pmx, tmp, reg); | 1795 | |
1797 | __global_unlock2(flags); | 1796 | /* Write register field */ |
1797 | __global_lock2(flags); | ||
1798 | tmp = pmx_read(pmx, reg); | ||
1799 | tmp &= ~mask; | ||
1800 | if (arg) | ||
1801 | tmp |= val << shift; | ||
1802 | pmx_write(pmx, tmp, reg); | ||
1803 | __global_unlock2(flags); | ||
1804 | } /* for each config */ | ||
1798 | 1805 | ||
1799 | return 0; | 1806 | return 0; |
1800 | } | 1807 | } |
@@ -1894,68 +1901,81 @@ static int tz1090_pinconf_group_get(struct pinctrl_dev *pctldev, | |||
1894 | } | 1901 | } |
1895 | 1902 | ||
1896 | static int tz1090_pinconf_group_set(struct pinctrl_dev *pctldev, | 1903 | static int tz1090_pinconf_group_set(struct pinctrl_dev *pctldev, |
1897 | unsigned int group, unsigned long config) | 1904 | unsigned int group, unsigned long *configs, |
1905 | unsigned num_configs) | ||
1898 | { | 1906 | { |
1899 | struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | 1907 | struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); |
1900 | const struct tz1090_pingroup *g; | 1908 | const struct tz1090_pingroup *g; |
1901 | enum pin_config_param param = pinconf_to_config_param(config); | 1909 | enum pin_config_param param; |
1902 | unsigned int arg, pin, i; | 1910 | unsigned int arg, pin, i; |
1903 | const unsigned int *pit; | 1911 | const unsigned int *pit; |
1904 | int ret; | 1912 | int ret; |
1905 | u32 reg, width, mask, shift, val; | 1913 | u32 reg, width, mask, shift, val; |
1906 | unsigned long flags; | 1914 | unsigned long flags; |
1907 | const int *map; | 1915 | const int *map; |
1916 | int j; | ||
1908 | 1917 | ||
1909 | if (group >= ARRAY_SIZE(tz1090_groups)) { | 1918 | if (group >= ARRAY_SIZE(tz1090_groups)) { |
1910 | pin = group - ARRAY_SIZE(tz1090_groups); | 1919 | pin = group - ARRAY_SIZE(tz1090_groups); |
1911 | return tz1090_pinconf_set(pctldev, pin, config); | 1920 | return tz1090_pinconf_set(pctldev, pin, configs, num_configs); |
1912 | } | 1921 | } |
1913 | 1922 | ||
1914 | g = &tz1090_groups[group]; | 1923 | g = &tz1090_groups[group]; |
1915 | if (g->npins == 1) { | 1924 | if (g->npins == 1) { |
1916 | pin = g->pins[0]; | 1925 | pin = g->pins[0]; |
1917 | ret = tz1090_pinconf_set(pctldev, pin, config); | 1926 | ret = tz1090_pinconf_set(pctldev, pin, configs, num_configs); |
1918 | if (ret != -ENOTSUPP) | 1927 | if (ret != -ENOTSUPP) |
1919 | return ret; | 1928 | return ret; |
1920 | } | 1929 | } |
1921 | 1930 | ||
1922 | dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n", | 1931 | for (j = 0; j < num_configs; j++) { |
1923 | __func__, g->name, config); | 1932 | param = pinconf_to_config_param(configs[j]); |
1924 | 1933 | ||
1925 | /* Get register information */ | 1934 | dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n", |
1926 | ret = tz1090_pinconf_group_reg(pctldev, g, param, true, | 1935 | __func__, g->name, configs[j]); |
1927 | ®, &width, &mask, &shift, &map); | ||
1928 | if (ret < 0) { | ||
1929 | /* | ||
1930 | * Maybe we're trying to set a per-pin configuration of a group, | ||
1931 | * so do the pins one by one. This is mainly as a convenience. | ||
1932 | */ | ||
1933 | for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) { | ||
1934 | ret = tz1090_pinconf_set(pctldev, *pit, config); | ||
1935 | if (ret) | ||
1936 | return ret; | ||
1937 | } | ||
1938 | return 0; | ||
1939 | } | ||
1940 | 1936 | ||
1941 | /* Unpack argument and map it to register value */ | 1937 | /* Get register information */ |
1942 | arg = pinconf_to_config_argument(config); | 1938 | ret = tz1090_pinconf_group_reg(pctldev, g, param, true, ®, |
1943 | for (i = 0; i < BIT(width); ++i) { | 1939 | &width, &mask, &shift, &map); |
1944 | if (map[i] == arg || (map[i] == -EINVAL && !arg)) { | 1940 | if (ret < 0) { |
1945 | /* Write register field */ | 1941 | /* |
1946 | __global_lock2(flags); | 1942 | * Maybe we're trying to set a per-pin configuration |
1947 | val = pmx_read(pmx, reg); | 1943 | * of a group, so do the pins one by one. This is |
1948 | val &= ~mask; | 1944 | * mainly as a convenience. |
1949 | val |= i << shift; | 1945 | */ |
1950 | pmx_write(pmx, val, reg); | 1946 | for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) { |
1951 | __global_unlock2(flags); | 1947 | ret = tz1090_pinconf_set(pctldev, *pit, configs, |
1948 | num_configs); | ||
1949 | if (ret) | ||
1950 | return ret; | ||
1951 | } | ||
1952 | return 0; | 1952 | return 0; |
1953 | } | 1953 | } |
1954 | } | ||
1955 | 1954 | ||
1956 | dev_dbg(pctldev->dev, "%s: arg %u not supported\n", | 1955 | /* Unpack argument and map it to register value */ |
1957 | __func__, arg); | 1956 | arg = pinconf_to_config_argument(configs[j]); |
1958 | return -EINVAL; | 1957 | for (i = 0; i < BIT(width); ++i) { |
1958 | if (map[i] == arg || (map[i] == -EINVAL && !arg)) { | ||
1959 | /* Write register field */ | ||
1960 | __global_lock2(flags); | ||
1961 | val = pmx_read(pmx, reg); | ||
1962 | val &= ~mask; | ||
1963 | val |= i << shift; | ||
1964 | pmx_write(pmx, val, reg); | ||
1965 | __global_unlock2(flags); | ||
1966 | goto next_config; | ||
1967 | } | ||
1968 | } | ||
1969 | |||
1970 | dev_dbg(pctldev->dev, "%s: arg %u not supported\n", | ||
1971 | __func__, arg); | ||
1972 | return -EINVAL; | ||
1973 | |||
1974 | next_config: | ||
1975 | ; | ||
1976 | } /* for each config */ | ||
1977 | |||
1978 | return 0; | ||
1959 | } | 1979 | } |
1960 | 1980 | ||
1961 | static struct pinconf_ops tz1090_pinconf_ops = { | 1981 | static struct pinconf_ops tz1090_pinconf_ops = { |