aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrygorii Strashko <grygorii.strashko@ti.com>2014-09-03 13:05:33 -0400
committerLinus Walleij <linus.walleij@linaro.org>2014-09-16 17:40:05 -0400
commit5a3e3f88b0a10f8b5baf224ebda5916195fb8745 (patch)
tree1295a7f780877edd44cdb468763f4126ba0705d8
parent2c341d62eb4b697793c29da51fda64328df5ff59 (diff)
gpio: syscon: retrive syscon node and regs offsets from dt
This patch adds handling of new "gpio,syscon-dev" DT property, which allows to specify syscon node and data/direction registers offsets in DT. "gpio,syscon-dev" has following format: gpio,syscon-dev = <&syscon_dev data_reg_offset [direction_reg_offset]>; where - syscon_dev - phandle on syscon node - data_reg_offset - offset of data register (in bytes) - direction_reg_offset - offset of dirrection register (optional, in bytes) for example: gpio,syscon-dev = <&devctrl 0x254>; In such way, the support of multiple Syscon GPIO devices is added. Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/gpio/gpio-syscon.c51
1 files changed, 43 insertions, 8 deletions
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
index d50ff9363c81..049391bf80ee 100644
--- a/drivers/gpio/gpio-syscon.c
+++ b/drivers/gpio/gpio-syscon.c
@@ -55,6 +55,8 @@ struct syscon_gpio_priv {
55 struct gpio_chip chip; 55 struct gpio_chip chip;
56 struct regmap *syscon; 56 struct regmap *syscon;
57 const struct syscon_gpio_data *data; 57 const struct syscon_gpio_data *data;
58 u32 dreg_offset;
59 u32 dir_reg_offset;
58}; 60};
59 61
60static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip) 62static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
@@ -65,9 +67,11 @@ static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
65static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) 67static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
66{ 68{
67 struct syscon_gpio_priv *priv = to_syscon_gpio(chip); 69 struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
68 unsigned int val, offs = priv->data->dat_bit_offset + offset; 70 unsigned int val, offs;
69 int ret; 71 int ret;
70 72
73 offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
74
71 ret = regmap_read(priv->syscon, 75 ret = regmap_read(priv->syscon,
72 (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val); 76 (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val);
73 if (ret) 77 if (ret)
@@ -79,7 +83,9 @@ static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
79static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val) 83static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
80{ 84{
81 struct syscon_gpio_priv *priv = to_syscon_gpio(chip); 85 struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
82 unsigned int offs = priv->data->dat_bit_offset + offset; 86 unsigned int offs;
87
88 offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
83 89
84 regmap_update_bits(priv->syscon, 90 regmap_update_bits(priv->syscon,
85 (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, 91 (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
@@ -92,7 +98,10 @@ static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
92 struct syscon_gpio_priv *priv = to_syscon_gpio(chip); 98 struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
93 99
94 if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { 100 if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
95 unsigned int offs = priv->data->dir_bit_offset + offset; 101 unsigned int offs;
102
103 offs = priv->dir_reg_offset +
104 priv->data->dir_bit_offset + offset;
96 105
97 regmap_update_bits(priv->syscon, 106 regmap_update_bits(priv->syscon,
98 (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, 107 (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
@@ -107,7 +116,10 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
107 struct syscon_gpio_priv *priv = to_syscon_gpio(chip); 116 struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
108 117
109 if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { 118 if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
110 unsigned int offs = priv->data->dir_bit_offset + offset; 119 unsigned int offs;
120
121 offs = priv->dir_reg_offset +
122 priv->data->dir_bit_offset + offset;
111 123
112 regmap_update_bits(priv->syscon, 124 regmap_update_bits(priv->syscon,
113 (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, 125 (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
@@ -142,6 +154,8 @@ static int syscon_gpio_probe(struct platform_device *pdev)
142 struct device *dev = &pdev->dev; 154 struct device *dev = &pdev->dev;
143 const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev); 155 const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev);
144 struct syscon_gpio_priv *priv; 156 struct syscon_gpio_priv *priv;
157 struct device_node *np = dev->of_node;
158 int ret;
145 159
146 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 160 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
147 if (!priv) 161 if (!priv)
@@ -149,10 +163,31 @@ static int syscon_gpio_probe(struct platform_device *pdev)
149 163
150 priv->data = of_id->data; 164 priv->data = of_id->data;
151 165
152 priv->syscon = 166 if (priv->data->compatible) {
153 syscon_regmap_lookup_by_compatible(priv->data->compatible); 167 priv->syscon = syscon_regmap_lookup_by_compatible(
154 if (IS_ERR(priv->syscon)) 168 priv->data->compatible);
155 return PTR_ERR(priv->syscon); 169 if (IS_ERR(priv->syscon))
170 return PTR_ERR(priv->syscon);
171 } else {
172 priv->syscon =
173 syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev");
174 if (IS_ERR(priv->syscon))
175 return PTR_ERR(priv->syscon);
176
177 ret = of_property_read_u32_index(np, "gpio,syscon-dev", 1,
178 &priv->dreg_offset);
179 if (ret)
180 dev_err(dev, "can't read the data register offset!\n");
181
182 priv->dreg_offset <<= 3;
183
184 ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2,
185 &priv->dir_reg_offset);
186 if (ret)
187 dev_err(dev, "can't read the dir register offset!\n");
188
189 priv->dir_reg_offset <<= 3;
190 }
156 191
157 priv->chip.dev = dev; 192 priv->chip.dev = dev;
158 priv->chip.owner = THIS_MODULE; 193 priv->chip.owner = THIS_MODULE;