diff options
Diffstat (limited to 'drivers/gpio/gpio-omap.c')
-rw-r--r-- | drivers/gpio/gpio-omap.c | 88 |
1 files changed, 86 insertions, 2 deletions
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index d1afedf4dcbf..e81008678a38 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c | |||
@@ -77,6 +77,8 @@ struct gpio_bank { | |||
77 | bool workaround_enabled; | 77 | bool workaround_enabled; |
78 | 78 | ||
79 | void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable); | 79 | void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable); |
80 | void (*set_dataout_multiple)(struct gpio_bank *bank, | ||
81 | unsigned long *mask, unsigned long *bits); | ||
80 | int (*get_context_loss_count)(struct device *dev); | 82 | int (*get_context_loss_count)(struct device *dev); |
81 | 83 | ||
82 | struct omap_gpio_reg_offs *regs; | 84 | struct omap_gpio_reg_offs *regs; |
@@ -161,6 +163,51 @@ static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset) | |||
161 | return (readl_relaxed(reg) & (BIT(offset))) != 0; | 163 | return (readl_relaxed(reg) & (BIT(offset))) != 0; |
162 | } | 164 | } |
163 | 165 | ||
166 | /* set multiple data out values using dedicate set/clear register */ | ||
167 | static void omap_set_gpio_dataout_reg_multiple(struct gpio_bank *bank, | ||
168 | unsigned long *mask, | ||
169 | unsigned long *bits) | ||
170 | { | ||
171 | void __iomem *reg = bank->base; | ||
172 | u32 l; | ||
173 | |||
174 | l = *bits & *mask; | ||
175 | writel_relaxed(l, reg + bank->regs->set_dataout); | ||
176 | bank->context.dataout |= l; | ||
177 | |||
178 | l = ~*bits & *mask; | ||
179 | writel_relaxed(l, reg + bank->regs->clr_dataout); | ||
180 | bank->context.dataout &= ~l; | ||
181 | } | ||
182 | |||
183 | /* set multiple data out values using mask register */ | ||
184 | static void omap_set_gpio_dataout_mask_multiple(struct gpio_bank *bank, | ||
185 | unsigned long *mask, | ||
186 | unsigned long *bits) | ||
187 | { | ||
188 | void __iomem *reg = bank->base + bank->regs->dataout; | ||
189 | u32 l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask); | ||
190 | |||
191 | writel_relaxed(l, reg); | ||
192 | bank->context.dataout = l; | ||
193 | } | ||
194 | |||
195 | static unsigned long omap_get_gpio_datain_multiple(struct gpio_bank *bank, | ||
196 | unsigned long *mask) | ||
197 | { | ||
198 | void __iomem *reg = bank->base + bank->regs->datain; | ||
199 | |||
200 | return readl_relaxed(reg) & *mask; | ||
201 | } | ||
202 | |||
203 | static unsigned long omap_get_gpio_dataout_multiple(struct gpio_bank *bank, | ||
204 | unsigned long *mask) | ||
205 | { | ||
206 | void __iomem *reg = bank->base + bank->regs->dataout; | ||
207 | |||
208 | return readl_relaxed(reg) & *mask; | ||
209 | } | ||
210 | |||
164 | static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) | 211 | static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) |
165 | { | 212 | { |
166 | int l = readl_relaxed(base + reg); | 213 | int l = readl_relaxed(base + reg); |
@@ -968,6 +1015,26 @@ static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value) | |||
968 | return 0; | 1015 | return 0; |
969 | } | 1016 | } |
970 | 1017 | ||
1018 | static int omap_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, | ||
1019 | unsigned long *bits) | ||
1020 | { | ||
1021 | struct gpio_bank *bank = gpiochip_get_data(chip); | ||
1022 | void __iomem *reg = bank->base + bank->regs->direction; | ||
1023 | unsigned long in = readl_relaxed(reg), l; | ||
1024 | |||
1025 | *bits = 0; | ||
1026 | |||
1027 | l = in & *mask; | ||
1028 | if (l) | ||
1029 | *bits |= omap_get_gpio_datain_multiple(bank, &l); | ||
1030 | |||
1031 | l = ~in & *mask; | ||
1032 | if (l) | ||
1033 | *bits |= omap_get_gpio_dataout_multiple(bank, &l); | ||
1034 | |||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
971 | static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset, | 1038 | static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset, |
972 | unsigned debounce) | 1039 | unsigned debounce) |
973 | { | 1040 | { |
@@ -1012,6 +1079,17 @@ static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |||
1012 | raw_spin_unlock_irqrestore(&bank->lock, flags); | 1079 | raw_spin_unlock_irqrestore(&bank->lock, flags); |
1013 | } | 1080 | } |
1014 | 1081 | ||
1082 | static void omap_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, | ||
1083 | unsigned long *bits) | ||
1084 | { | ||
1085 | struct gpio_bank *bank = gpiochip_get_data(chip); | ||
1086 | unsigned long flags; | ||
1087 | |||
1088 | raw_spin_lock_irqsave(&bank->lock, flags); | ||
1089 | bank->set_dataout_multiple(bank, mask, bits); | ||
1090 | raw_spin_unlock_irqrestore(&bank->lock, flags); | ||
1091 | } | ||
1092 | |||
1015 | /*---------------------------------------------------------------------*/ | 1093 | /*---------------------------------------------------------------------*/ |
1016 | 1094 | ||
1017 | static void omap_gpio_show_rev(struct gpio_bank *bank) | 1095 | static void omap_gpio_show_rev(struct gpio_bank *bank) |
@@ -1073,9 +1151,11 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) | |||
1073 | bank->chip.get_direction = omap_gpio_get_direction; | 1151 | bank->chip.get_direction = omap_gpio_get_direction; |
1074 | bank->chip.direction_input = omap_gpio_input; | 1152 | bank->chip.direction_input = omap_gpio_input; |
1075 | bank->chip.get = omap_gpio_get; | 1153 | bank->chip.get = omap_gpio_get; |
1154 | bank->chip.get_multiple = omap_gpio_get_multiple; | ||
1076 | bank->chip.direction_output = omap_gpio_output; | 1155 | bank->chip.direction_output = omap_gpio_output; |
1077 | bank->chip.set_config = omap_gpio_set_config; | 1156 | bank->chip.set_config = omap_gpio_set_config; |
1078 | bank->chip.set = omap_gpio_set; | 1157 | bank->chip.set = omap_gpio_set; |
1158 | bank->chip.set_multiple = omap_gpio_set_multiple; | ||
1079 | if (bank->is_mpuio) { | 1159 | if (bank->is_mpuio) { |
1080 | bank->chip.label = "mpuio"; | 1160 | bank->chip.label = "mpuio"; |
1081 | if (bank->regs->wkup_en) | 1161 | if (bank->regs->wkup_en) |
@@ -1209,10 +1289,14 @@ static int omap_gpio_probe(struct platform_device *pdev) | |||
1209 | pdata->get_context_loss_count; | 1289 | pdata->get_context_loss_count; |
1210 | } | 1290 | } |
1211 | 1291 | ||
1212 | if (bank->regs->set_dataout && bank->regs->clr_dataout) | 1292 | if (bank->regs->set_dataout && bank->regs->clr_dataout) { |
1213 | bank->set_dataout = omap_set_gpio_dataout_reg; | 1293 | bank->set_dataout = omap_set_gpio_dataout_reg; |
1214 | else | 1294 | bank->set_dataout_multiple = omap_set_gpio_dataout_reg_multiple; |
1295 | } else { | ||
1215 | bank->set_dataout = omap_set_gpio_dataout_mask; | 1296 | bank->set_dataout = omap_set_gpio_dataout_mask; |
1297 | bank->set_dataout_multiple = | ||
1298 | omap_set_gpio_dataout_mask_multiple; | ||
1299 | } | ||
1216 | 1300 | ||
1217 | raw_spin_lock_init(&bank->lock); | 1301 | raw_spin_lock_init(&bank->lock); |
1218 | raw_spin_lock_init(&bank->wa_lock); | 1302 | raw_spin_lock_init(&bank->wa_lock); |