diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-02-10 14:35:36 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-02-10 14:35:36 -0500 |
commit | 4ba24fef3eb3b142197135223b90ced2f319cd53 (patch) | |
tree | a20c125b27740ec7b4c761b11d801108e1b316b2 /drivers/gpio/gpio-syscon.c | |
parent | 47c1ffb2b6b630894e9a16442611c056ab21c057 (diff) | |
parent | 98a4a59ee31a12105a2b84f5b8b515ac2cb208ef (diff) |
Merge branch 'next' into for-linus
Prepare first round of input updates for 3.20.
Diffstat (limited to 'drivers/gpio/gpio-syscon.c')
-rw-r--r-- | drivers/gpio/gpio-syscon.c | 95 |
1 files changed, 84 insertions, 11 deletions
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index 30884fbc750d..257e2989215c 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c | |||
@@ -37,6 +37,8 @@ | |||
37 | * dat_bit_offset: Offset (in bits) to the first GPIO bit. | 37 | * dat_bit_offset: Offset (in bits) to the first GPIO bit. |
38 | * dir_bit_offset: Optional offset (in bits) to the first bit to switch | 38 | * dir_bit_offset: Optional offset (in bits) to the first bit to switch |
39 | * GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag). | 39 | * GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag). |
40 | * set: HW specific callback to assigns output value | ||
41 | * for signal "offset" | ||
40 | */ | 42 | */ |
41 | 43 | ||
42 | struct syscon_gpio_data { | 44 | struct syscon_gpio_data { |
@@ -45,12 +47,16 @@ struct syscon_gpio_data { | |||
45 | unsigned int bit_count; | 47 | unsigned int bit_count; |
46 | unsigned int dat_bit_offset; | 48 | unsigned int dat_bit_offset; |
47 | unsigned int dir_bit_offset; | 49 | unsigned int dir_bit_offset; |
50 | void (*set)(struct gpio_chip *chip, | ||
51 | unsigned offset, int value); | ||
48 | }; | 52 | }; |
49 | 53 | ||
50 | struct syscon_gpio_priv { | 54 | struct syscon_gpio_priv { |
51 | struct gpio_chip chip; | 55 | struct gpio_chip chip; |
52 | struct regmap *syscon; | 56 | struct regmap *syscon; |
53 | const struct syscon_gpio_data *data; | 57 | const struct syscon_gpio_data *data; |
58 | u32 dreg_offset; | ||
59 | u32 dir_reg_offset; | ||
54 | }; | 60 | }; |
55 | 61 | ||
56 | 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) |
@@ -61,9 +67,11 @@ static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip) | |||
61 | static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) | 67 | static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) |
62 | { | 68 | { |
63 | struct syscon_gpio_priv *priv = to_syscon_gpio(chip); | 69 | struct syscon_gpio_priv *priv = to_syscon_gpio(chip); |
64 | unsigned int val, offs = priv->data->dat_bit_offset + offset; | 70 | unsigned int val, offs; |
65 | int ret; | 71 | int ret; |
66 | 72 | ||
73 | offs = priv->dreg_offset + priv->data->dat_bit_offset + offset; | ||
74 | |||
67 | ret = regmap_read(priv->syscon, | 75 | ret = regmap_read(priv->syscon, |
68 | (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val); | 76 | (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val); |
69 | if (ret) | 77 | if (ret) |
@@ -75,7 +83,9 @@ static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) | |||
75 | 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) |
76 | { | 84 | { |
77 | struct syscon_gpio_priv *priv = to_syscon_gpio(chip); | 85 | struct syscon_gpio_priv *priv = to_syscon_gpio(chip); |
78 | 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; | ||
79 | 89 | ||
80 | regmap_update_bits(priv->syscon, | 90 | regmap_update_bits(priv->syscon, |
81 | (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, | 91 | (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, |
@@ -88,7 +98,10 @@ static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset) | |||
88 | struct syscon_gpio_priv *priv = to_syscon_gpio(chip); | 98 | struct syscon_gpio_priv *priv = to_syscon_gpio(chip); |
89 | 99 | ||
90 | if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { | 100 | if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { |
91 | 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; | ||
92 | 105 | ||
93 | regmap_update_bits(priv->syscon, | 106 | regmap_update_bits(priv->syscon, |
94 | (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, | 107 | (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, |
@@ -103,7 +116,10 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) | |||
103 | struct syscon_gpio_priv *priv = to_syscon_gpio(chip); | 116 | struct syscon_gpio_priv *priv = to_syscon_gpio(chip); |
104 | 117 | ||
105 | if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { | 118 | if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { |
106 | 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; | ||
107 | 123 | ||
108 | regmap_update_bits(priv->syscon, | 124 | regmap_update_bits(priv->syscon, |
109 | (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, | 125 | (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, |
@@ -111,7 +127,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) | |||
111 | BIT(offs % SYSCON_REG_BITS)); | 127 | BIT(offs % SYSCON_REG_BITS)); |
112 | } | 128 | } |
113 | 129 | ||
114 | syscon_gpio_set(chip, offset, val); | 130 | priv->data->set(chip, offset, val); |
115 | 131 | ||
116 | return 0; | 132 | return 0; |
117 | } | 133 | } |
@@ -124,11 +140,46 @@ static const struct syscon_gpio_data clps711x_mctrl_gpio = { | |||
124 | .dat_bit_offset = 0x40 * 8 + 8, | 140 | .dat_bit_offset = 0x40 * 8 + 8, |
125 | }; | 141 | }; |
126 | 142 | ||
143 | #define KEYSTONE_LOCK_BIT BIT(0) | ||
144 | |||
145 | static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | ||
146 | { | ||
147 | struct syscon_gpio_priv *priv = to_syscon_gpio(chip); | ||
148 | unsigned int offs; | ||
149 | int ret; | ||
150 | |||
151 | offs = priv->dreg_offset + priv->data->dat_bit_offset + offset; | ||
152 | |||
153 | if (!val) | ||
154 | return; | ||
155 | |||
156 | ret = regmap_update_bits( | ||
157 | priv->syscon, | ||
158 | (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, | ||
159 | BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT, | ||
160 | BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT); | ||
161 | if (ret < 0) | ||
162 | dev_err(chip->dev, "gpio write failed ret(%d)\n", ret); | ||
163 | } | ||
164 | |||
165 | static const struct syscon_gpio_data keystone_dsp_gpio = { | ||
166 | /* ARM Keystone 2 */ | ||
167 | .compatible = NULL, | ||
168 | .flags = GPIO_SYSCON_FEAT_OUT, | ||
169 | .bit_count = 28, | ||
170 | .dat_bit_offset = 4, | ||
171 | .set = keystone_gpio_set, | ||
172 | }; | ||
173 | |||
127 | static const struct of_device_id syscon_gpio_ids[] = { | 174 | static const struct of_device_id syscon_gpio_ids[] = { |
128 | { | 175 | { |
129 | .compatible = "cirrus,clps711x-mctrl-gpio", | 176 | .compatible = "cirrus,clps711x-mctrl-gpio", |
130 | .data = &clps711x_mctrl_gpio, | 177 | .data = &clps711x_mctrl_gpio, |
131 | }, | 178 | }, |
179 | { | ||
180 | .compatible = "ti,keystone-dsp-gpio", | ||
181 | .data = &keystone_dsp_gpio, | ||
182 | }, | ||
132 | { } | 183 | { } |
133 | }; | 184 | }; |
134 | MODULE_DEVICE_TABLE(of, syscon_gpio_ids); | 185 | MODULE_DEVICE_TABLE(of, syscon_gpio_ids); |
@@ -138,6 +189,8 @@ static int syscon_gpio_probe(struct platform_device *pdev) | |||
138 | struct device *dev = &pdev->dev; | 189 | struct device *dev = &pdev->dev; |
139 | const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev); | 190 | const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev); |
140 | struct syscon_gpio_priv *priv; | 191 | struct syscon_gpio_priv *priv; |
192 | struct device_node *np = dev->of_node; | ||
193 | int ret; | ||
141 | 194 | ||
142 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 195 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
143 | if (!priv) | 196 | if (!priv) |
@@ -145,10 +198,31 @@ static int syscon_gpio_probe(struct platform_device *pdev) | |||
145 | 198 | ||
146 | priv->data = of_id->data; | 199 | priv->data = of_id->data; |
147 | 200 | ||
148 | priv->syscon = | 201 | if (priv->data->compatible) { |
149 | syscon_regmap_lookup_by_compatible(priv->data->compatible); | 202 | priv->syscon = syscon_regmap_lookup_by_compatible( |
150 | if (IS_ERR(priv->syscon)) | 203 | priv->data->compatible); |
151 | return PTR_ERR(priv->syscon); | 204 | if (IS_ERR(priv->syscon)) |
205 | return PTR_ERR(priv->syscon); | ||
206 | } else { | ||
207 | priv->syscon = | ||
208 | syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev"); | ||
209 | if (IS_ERR(priv->syscon)) | ||
210 | return PTR_ERR(priv->syscon); | ||
211 | |||
212 | ret = of_property_read_u32_index(np, "gpio,syscon-dev", 1, | ||
213 | &priv->dreg_offset); | ||
214 | if (ret) | ||
215 | dev_err(dev, "can't read the data register offset!\n"); | ||
216 | |||
217 | priv->dreg_offset <<= 3; | ||
218 | |||
219 | ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2, | ||
220 | &priv->dir_reg_offset); | ||
221 | if (ret) | ||
222 | dev_err(dev, "can't read the dir register offset!\n"); | ||
223 | |||
224 | priv->dir_reg_offset <<= 3; | ||
225 | } | ||
152 | 226 | ||
153 | priv->chip.dev = dev; | 227 | priv->chip.dev = dev; |
154 | priv->chip.owner = THIS_MODULE; | 228 | priv->chip.owner = THIS_MODULE; |
@@ -159,7 +233,7 @@ static int syscon_gpio_probe(struct platform_device *pdev) | |||
159 | if (priv->data->flags & GPIO_SYSCON_FEAT_IN) | 233 | if (priv->data->flags & GPIO_SYSCON_FEAT_IN) |
160 | priv->chip.direction_input = syscon_gpio_dir_in; | 234 | priv->chip.direction_input = syscon_gpio_dir_in; |
161 | if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) { | 235 | if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) { |
162 | priv->chip.set = syscon_gpio_set; | 236 | priv->chip.set = priv->data->set ? : syscon_gpio_set; |
163 | priv->chip.direction_output = syscon_gpio_dir_out; | 237 | priv->chip.direction_output = syscon_gpio_dir_out; |
164 | } | 238 | } |
165 | 239 | ||
@@ -179,7 +253,6 @@ static int syscon_gpio_remove(struct platform_device *pdev) | |||
179 | static struct platform_driver syscon_gpio_driver = { | 253 | static struct platform_driver syscon_gpio_driver = { |
180 | .driver = { | 254 | .driver = { |
181 | .name = "gpio-syscon", | 255 | .name = "gpio-syscon", |
182 | .owner = THIS_MODULE, | ||
183 | .of_match_table = syscon_gpio_ids, | 256 | .of_match_table = syscon_gpio_ids, |
184 | }, | 257 | }, |
185 | .probe = syscon_gpio_probe, | 258 | .probe = syscon_gpio_probe, |