diff options
author | Grygorii Strashko <grygorii.strashko@ti.com> | 2014-09-03 13:05:33 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2014-09-16 17:40:05 -0400 |
commit | 5a3e3f88b0a10f8b5baf224ebda5916195fb8745 (patch) | |
tree | 1295a7f780877edd44cdb468763f4126ba0705d8 | |
parent | 2c341d62eb4b697793c29da51fda64328df5ff59 (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.c | 51 |
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 | ||
60 | static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip) | 62 | static 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) | |||
65 | static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) | 67 | static 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) | |||
79 | static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | 83 | static 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; |