aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-syscon.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2015-02-10 14:35:36 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-02-10 14:35:36 -0500
commit4ba24fef3eb3b142197135223b90ced2f319cd53 (patch)
treea20c125b27740ec7b4c761b11d801108e1b316b2 /drivers/gpio/gpio-syscon.c
parent47c1ffb2b6b630894e9a16442611c056ab21c057 (diff)
parent98a4a59ee31a12105a2b84f5b8b515ac2cb208ef (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.c95
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
42struct syscon_gpio_data { 44struct 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
50struct syscon_gpio_priv { 54struct 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
56static 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)
@@ -61,9 +67,11 @@ static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
61static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) 67static 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)
75static 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)
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
145static 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
165static 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
127static const struct of_device_id syscon_gpio_ids[] = { 174static 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};
134MODULE_DEVICE_TABLE(of, syscon_gpio_ids); 185MODULE_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)
179static struct platform_driver syscon_gpio_driver = { 253static 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,