Skip to content

Commit a3d37e0

Browse files
billy-tsaiBartosz Golaszewski
authored andcommitted
gpio: aspeed-sgpio: Create llops to handle hardware access
Add low-level operations (llops) to abstract the register access for SGPIO registers. With this abstraction layer, the driver can separate the hardware and software logic, making it easier to extend the driver to support different hardware register layouts. The llops abstraction changes the programming semantics from bitmask-based writes to a value-based interface. Instead of passing a pre-shifted bitmask to the caller, the driver now passes: - the GPIO offset, and - the value to be set (0 or 1), and the llops helpers are responsible for deriving the correct register and bit position internally. As a result, assignments such as: type0 = 1; type1 = 1; type2 = 1; do not represent a behavioral change. They indicate that the bit corresponding to the given GPIO offset should be set, with the actual bit manipulation handled by llops. Reviewed-by: Linus Walleij <linusw@kernel.org> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com> Link: https://lore.kernel.org/r/20260123-upstream_sgpio-v2-3-69cfd1631400@aspeedtech.com Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
1 parent 5928e0d commit a3d37e0

1 file changed

Lines changed: 104 additions & 118 deletions

File tree

drivers/gpio/gpio-aspeed-sgpio.c

Lines changed: 104 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
struct aspeed_sgpio_pdata {
2929
const u32 pin_mask;
30+
const struct aspeed_sgpio_llops *llops;
3031
};
3132

3233
struct aspeed_sgpio {
@@ -36,6 +37,7 @@ struct aspeed_sgpio {
3637
raw_spinlock_t lock;
3738
void __iomem *base;
3839
int irq;
40+
const struct aspeed_sgpio_pdata *pdata;
3941
};
4042

4143
struct aspeed_sgpio_bank {
@@ -90,16 +92,25 @@ enum aspeed_sgpio_reg {
9092
reg_tolerance,
9193
};
9294

95+
struct aspeed_sgpio_llops {
96+
void (*reg_bit_set)(struct aspeed_sgpio *gpio, unsigned int offset,
97+
const enum aspeed_sgpio_reg reg, bool val);
98+
bool (*reg_bit_get)(struct aspeed_sgpio *gpio, unsigned int offset,
99+
const enum aspeed_sgpio_reg reg);
100+
int (*reg_bank_get)(struct aspeed_sgpio *gpio, unsigned int offset,
101+
const enum aspeed_sgpio_reg reg);
102+
};
103+
93104
#define GPIO_VAL_VALUE 0x00
94105
#define GPIO_IRQ_ENABLE 0x00
95106
#define GPIO_IRQ_TYPE0 0x04
96107
#define GPIO_IRQ_TYPE1 0x08
97108
#define GPIO_IRQ_TYPE2 0x0C
98109
#define GPIO_IRQ_STATUS 0x10
99110

100-
static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
101-
const struct aspeed_sgpio_bank *bank,
102-
const enum aspeed_sgpio_reg reg)
111+
static void __iomem *aspeed_sgpio_g4_bank_reg(struct aspeed_sgpio *gpio,
112+
const struct aspeed_sgpio_bank *bank,
113+
const enum aspeed_sgpio_reg reg)
103114
{
104115
switch (reg) {
105116
case reg_val:
@@ -165,41 +176,25 @@ static bool aspeed_sgpio_is_input(unsigned int offset)
165176
static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
166177
{
167178
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
168-
const struct aspeed_sgpio_bank *bank = to_bank(offset);
169179
enum aspeed_sgpio_reg reg;
170180
int rc = 0;
171181

172182
guard(raw_spinlock_irqsave)(&gpio->lock);
173183

174184
reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata;
175-
rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
185+
rc = gpio->pdata->llops->reg_bit_get(gpio, offset, reg);
176186

177187
return rc;
178188
}
179189

180190
static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
181191
{
182192
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
183-
const struct aspeed_sgpio_bank *bank = to_bank(offset);
184-
void __iomem *addr_r, *addr_w;
185-
u32 reg = 0;
186193

187194
if (aspeed_sgpio_is_input(offset))
188195
return -EINVAL;
189196

190-
/* Since this is an output, read the cached value from rdata, then
191-
* update val. */
192-
addr_r = bank_reg(gpio, bank, reg_rdata);
193-
addr_w = bank_reg(gpio, bank, reg_val);
194-
195-
reg = ioread32(addr_r);
196-
197-
if (val)
198-
reg |= GPIO_BIT(offset);
199-
else
200-
reg &= ~GPIO_BIT(offset);
201-
202-
iowrite32(reg, addr_w);
197+
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_val, val);
203198

204199
return 0;
205200
}
@@ -238,69 +233,34 @@ static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
238233
return !!aspeed_sgpio_is_input(offset);
239234
}
240235

241-
static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
242-
struct aspeed_sgpio **gpio,
243-
const struct aspeed_sgpio_bank **bank,
244-
u32 *bit, int *offset)
245-
{
246-
struct aspeed_sgpio *internal;
247-
248-
*offset = irqd_to_hwirq(d);
249-
internal = irq_data_get_irq_chip_data(d);
250-
WARN_ON(!internal);
251-
252-
*gpio = internal;
253-
*bank = to_bank(*offset);
254-
*bit = GPIO_BIT(*offset);
255-
}
256236

257237
static void aspeed_sgpio_irq_ack(struct irq_data *d)
258238
{
259-
const struct aspeed_sgpio_bank *bank;
260-
struct aspeed_sgpio *gpio;
261-
void __iomem *status_addr;
262-
int offset;
263-
u32 bit;
264-
265-
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
266-
267-
status_addr = bank_reg(gpio, bank, reg_irq_status);
239+
struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
240+
int offset = irqd_to_hwirq(d);
268241

269242
guard(raw_spinlock_irqsave)(&gpio->lock);
270243

271-
iowrite32(bit, status_addr);
244+
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_status, 1);
272245
}
273246

274247
static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
275248
{
276-
const struct aspeed_sgpio_bank *bank;
277-
struct aspeed_sgpio *gpio;
278-
u32 reg, bit;
279-
void __iomem *addr;
280-
int offset;
281-
282-
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
283-
addr = bank_reg(gpio, bank, reg_irq_enable);
249+
struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
250+
int offset = irqd_to_hwirq(d);
284251

285252
/* Unmasking the IRQ */
286253
if (set)
287-
gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d));
288-
289-
scoped_guard(raw_spinlock_irqsave, &gpio->lock) {
290-
reg = ioread32(addr);
291-
if (set)
292-
reg |= bit;
293-
else
294-
reg &= ~bit;
295-
296-
iowrite32(reg, addr);
254+
gpiochip_enable_irq(&gpio->chip, offset);
255+
scoped_guard(raw_spinlock_irqsave, &gpio->lock)
256+
{
257+
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_enable,
258+
set);
297259
}
298260

299261
/* Masking the IRQ */
300262
if (!set)
301-
gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d));
302-
303-
263+
gpiochip_disable_irq(&gpio->chip, offset);
304264
}
305265

306266
static void aspeed_sgpio_irq_mask(struct irq_data *d)
@@ -318,51 +278,35 @@ static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
318278
u32 type0 = 0;
319279
u32 type1 = 0;
320280
u32 type2 = 0;
321-
u32 bit, reg;
322-
const struct aspeed_sgpio_bank *bank;
323281
irq_flow_handler_t handler;
324-
struct aspeed_sgpio *gpio;
325-
void __iomem *addr;
326-
int offset;
327-
328-
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
282+
struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
283+
int offset = irqd_to_hwirq(d);
329284

330285
switch (type & IRQ_TYPE_SENSE_MASK) {
331286
case IRQ_TYPE_EDGE_BOTH:
332-
type2 |= bit;
287+
type2 = 1;
333288
fallthrough;
334289
case IRQ_TYPE_EDGE_RISING:
335-
type0 |= bit;
290+
type0 = 1;
336291
fallthrough;
337292
case IRQ_TYPE_EDGE_FALLING:
338293
handler = handle_edge_irq;
339294
break;
340295
case IRQ_TYPE_LEVEL_HIGH:
341-
type0 |= bit;
296+
type0 = 1;
342297
fallthrough;
343298
case IRQ_TYPE_LEVEL_LOW:
344-
type1 |= bit;
299+
type1 = 1;
345300
handler = handle_level_irq;
346301
break;
347302
default:
348303
return -EINVAL;
349304
}
350305

351306
scoped_guard(raw_spinlock_irqsave, &gpio->lock) {
352-
addr = bank_reg(gpio, bank, reg_irq_type0);
353-
reg = ioread32(addr);
354-
reg = (reg & ~bit) | type0;
355-
iowrite32(reg, addr);
356-
357-
addr = bank_reg(gpio, bank, reg_irq_type1);
358-
reg = ioread32(addr);
359-
reg = (reg & ~bit) | type1;
360-
iowrite32(reg, addr);
361-
362-
addr = bank_reg(gpio, bank, reg_irq_type2);
363-
reg = ioread32(addr);
364-
reg = (reg & ~bit) | type2;
365-
iowrite32(reg, addr);
307+
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type0, type0);
308+
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type1, type1);
309+
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type2, type2);
366310
}
367311

368312
irq_set_handler_locked(d, handler);
@@ -381,9 +325,7 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
381325
chained_irq_enter(ic, desc);
382326

383327
for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
384-
const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
385-
386-
reg = ioread32(bank_reg(data, bank, reg_irq_status));
328+
reg = data->pdata->llops->reg_bank_get(data, i << 6, reg_irq_status);
387329

388330
for_each_set_bit(p, &reg, 32)
389331
generic_handle_domain_irq(gc->irq.domain, (i * 32 + p) * 2);
@@ -394,12 +336,8 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
394336

395337
static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
396338
{
397-
const struct aspeed_sgpio_bank *bank;
398-
struct aspeed_sgpio *gpio;
399-
u32 bit;
400-
int offset;
339+
struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
401340

402-
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
403341
seq_puts(p, dev_name(gpio->dev));
404342
}
405343

@@ -447,7 +385,7 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
447385

448386
/* Apply default IRQ settings */
449387
for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
450-
bank = &aspeed_sgpio_banks[i];
388+
bank = &aspeed_sgpio_banks[i];
451389
/* set falling or level-low irq */
452390
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
453391
/* trigger type is edge */
@@ -459,29 +397,78 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
459397
return 0;
460398
}
461399

400+
static void aspeed_sgpio_g4_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset,
401+
const enum aspeed_sgpio_reg reg, bool val)
402+
{
403+
const struct aspeed_sgpio_bank *bank = to_bank(offset);
404+
void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg);
405+
u32 temp;
406+
407+
if (reg == reg_val) {
408+
/* Since this is an output, read the cached value from rdata, then update val. */
409+
addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_rdata);
410+
temp = ioread32(addr);
411+
if (val)
412+
temp |= GPIO_BIT(offset);
413+
else
414+
temp &= ~GPIO_BIT(offset);
415+
416+
addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_val);
417+
iowrite32(temp, addr);
418+
} else if (reg == reg_irq_status) {
419+
if (val)
420+
iowrite32(GPIO_BIT(offset), addr);
421+
} else {
422+
/* When setting other registers, we read from the register itself */
423+
temp = ioread32(addr);
424+
if (val)
425+
temp |= GPIO_BIT(offset);
426+
else
427+
temp &= ~GPIO_BIT(offset);
428+
iowrite32(temp, addr);
429+
}
430+
}
431+
432+
static bool aspeed_sgpio_g4_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset,
433+
const enum aspeed_sgpio_reg reg)
434+
{
435+
const struct aspeed_sgpio_bank *bank = to_bank(offset);
436+
void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg);
437+
438+
return !!(ioread32(addr) & GPIO_BIT(offset));
439+
}
440+
441+
static int aspeed_sgpio_g4_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset,
442+
const enum aspeed_sgpio_reg reg)
443+
{
444+
const struct aspeed_sgpio_bank *bank = to_bank(offset);
445+
void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg);
446+
447+
if (reg == reg_irq_status)
448+
return ioread32(addr);
449+
else
450+
return -EOPNOTSUPP;
451+
}
452+
453+
static const struct aspeed_sgpio_llops aspeed_sgpio_g4_llops = {
454+
.reg_bit_set = aspeed_sgpio_g4_reg_bit_set,
455+
.reg_bit_get = aspeed_sgpio_g4_reg_bit_get,
456+
.reg_bank_get = aspeed_sgpio_g4_reg_bank_get,
457+
};
458+
462459
static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = {
463460
.pin_mask = GENMASK(9, 6),
461+
.llops = &aspeed_sgpio_g4_llops,
464462
};
465463

466464
static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip,
467465
unsigned int offset, bool enable)
468466
{
469467
struct aspeed_sgpio *gpio = gpiochip_get_data(chip);
470-
void __iomem *reg;
471-
u32 val;
472-
473-
reg = bank_reg(gpio, to_bank(offset), reg_tolerance);
474468

475469
guard(raw_spinlock_irqsave)(&gpio->lock);
476470

477-
val = readl(reg);
478-
479-
if (enable)
480-
val |= GPIO_BIT(offset);
481-
else
482-
val &= ~GPIO_BIT(offset);
483-
484-
writel(val, reg);
471+
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_tolerance, enable);
485472

486473
return 0;
487474
}
@@ -500,6 +487,7 @@ static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset,
500487

501488
static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = {
502489
.pin_mask = GENMASK(10, 6),
490+
.llops = &aspeed_sgpio_g4_llops,
503491
};
504492

505493
static const struct of_device_id aspeed_sgpio_of_table[] = {
@@ -514,7 +502,6 @@ MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
514502
static int aspeed_sgpio_probe(struct platform_device *pdev)
515503
{
516504
u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask;
517-
const struct aspeed_sgpio_pdata *pdata;
518505
struct aspeed_sgpio *gpio;
519506
unsigned long apb_freq;
520507
int rc;
@@ -529,12 +516,11 @@ static int aspeed_sgpio_probe(struct platform_device *pdev)
529516

530517
gpio->dev = &pdev->dev;
531518

532-
pdata = device_get_match_data(&pdev->dev);
533-
if (!pdata)
519+
gpio->pdata = device_get_match_data(&pdev->dev);
520+
if (!gpio->pdata)
534521
return -EINVAL;
535522

536-
pin_mask = pdata->pin_mask;
537-
523+
pin_mask = gpio->pdata->pin_mask;
538524
rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios);
539525
if (rc < 0) {
540526
dev_err(&pdev->dev, "Could not read ngpios property\n");

0 commit comments

Comments
 (0)