1.1 --- a/pkg/devices/lib/gpio/src/jz4730.cc Fri Sep 22 21:56:34 2023 +0200
1.2 +++ b/pkg/devices/lib/gpio/src/jz4730.cc Sun Sep 24 01:53:43 2023 +0200
1.3 @@ -2,7 +2,7 @@
1.4 * GPIO driver for Ingenic JZ4730.
1.5 * (See below for additional copyright and licensing notices.)
1.6 *
1.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
1.8 + * Copyright (C) 2017, 2018, 2023 Paul Boddie <paul@boddie.org.uk>
1.9 *
1.10 * This program is free software; you can redistribute it and/or
1.11 * modify it under the terms of the GNU General Public License as
1.12 @@ -46,6 +46,7 @@
1.13 Irq_detect_lower = 0x018, // PxGPDLR
1.14 Irq_detect_upper = 0x01c, // PxGPDUR
1.15 Irq_enable = 0x020, // PxGPIER
1.16 + Irq_mask = 0x024, // PxGPIM
1.17 Irq_flag = 0x028, // PxGPFR
1.18 };
1.19
1.20 @@ -70,8 +71,6 @@
1.21 }
1.22 }
1.23
1.24 -
1.25 -
1.26 // IRQ control for each GPIO pin.
1.27
1.28 Gpio_jz4730_irq_pin::Gpio_jz4730_irq_pin(unsigned pin, Hw::Register_block<32> const ®s)
1.29 @@ -129,6 +128,9 @@
1.30 {
1.31 // Set the interrupt bit in the PxGPIER register.
1.32
1.33 + /* NOTE: This should use the Irq_mask/PxGPIM register, with the enable
1.34 + register actually setting IRQ mode. */
1.35 +
1.36 clear_reg_pin(Irq_enable);
1.37 }
1.38
1.39 @@ -137,6 +139,9 @@
1.40 // Set the interrupt bit in the PxGPIER register, first also clearing the
1.41 // flag bit in the PxGPFR register to allow interrupts to be delivered.
1.42
1.43 + /* NOTE: This should use the Irq_mask/PxGPIM register, with the enable
1.44 + register actually setting IRQ mode. */
1.45 +
1.46 clear_reg_pin(Irq_flag);
1.47 set_reg_pin(Irq_enable);
1.48 }
1.49 @@ -306,19 +311,23 @@
1.50 Gpio_jz4730_chip::_config(unsigned bitmap, unsigned mode)
1.51 {
1.52 uint32_t upper_mask, lower_mask;
1.53 - unsigned bitmap_values = bitmap;
1.54
1.55 switch (mode)
1.56 {
1.57 case Input:
1.58 case Irq:
1.59 - // Clear the direction flags below.
1.60 - bitmap_values = 0;
1.61 - // Fall through to the next case to complete the operation.
1.62 + // Clear the direction flags.
1.63 + _regs[Port_direction] = _regs[Port_direction] & ~bitmap;
1.64 +
1.65 + // Clear the port function for the bits.
1.66 + _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask);
1.67 + _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask);
1.68 + _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask);
1.69 + break;
1.70
1.71 case Output:
1.72 - // Clear the flags if set immediately above; otherwise, set them.
1.73 - _regs[Port_direction] = (_regs[Port_direction] & ~bitmap) | bitmap_values;
1.74 + // Set the direction flags.
1.75 + _regs[Port_direction] = _regs[Port_direction] | bitmap;
1.76
1.77 // Clear the port function for the bits.
1.78 _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask);
1.79 @@ -382,12 +391,15 @@
1.80 {
1.81 case Hw::Gpio_chip::Function_alt:
1.82 _get_bitmaps(bitmap, value, &upper, &lower);
1.83 - // Fall through to the next case to complete the operation.
1.84 + _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask);
1.85 + _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask) | upper;
1.86 + _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask) | lower;
1.87 + break;
1.88
1.89 case Hw::Gpio_chip::Function_gpio:
1.90 _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask);
1.91 - _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask) | upper;
1.92 - _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask) | lower;
1.93 + _regs[Port_function_upper] = _regs[Port_function_upper] & ~upper_mask;
1.94 + _regs[Port_function_lower] = _regs[Port_function_lower] & ~lower_mask;
1.95 break;
1.96
1.97 default:
1.98 @@ -406,6 +418,62 @@
1.99 *value = (_regs[reg] >> _pin_shift(pin)) & 1;
1.100 }
1.101
1.102 +// Return function and function-specific configuration for a pin.
1.103 +
1.104 +void
1.105 +Gpio_jz4730_chip::config_pad_get(unsigned pin, unsigned *func, unsigned *value)
1.106 +{
1.107 + unsigned detect, direction, pin_function, interrupt;
1.108 +
1.109 + // Get the pin function using the awkward register pairing.
1.110 +
1.111 + _get_pin_value(pin, Port_function_upper, Port_function_lower, &pin_function);
1.112 +
1.113 + if (pin_function)
1.114 + {
1.115 + *func = Hw::Gpio_chip::Function_alt;
1.116 + *value = pin_function;
1.117 + return;
1.118 + }
1.119 +
1.120 + config_get(pin, Irq_enable, &interrupt);
1.121 +
1.122 + if (interrupt)
1.123 + {
1.124 + _get_pin_value(pin, Irq_detect_upper, Irq_detect_lower, &detect);
1.125 +
1.126 + *func = Hw::Gpio_chip::Function_irq;
1.127 +
1.128 + switch (detect)
1.129 + {
1.130 + case 0: *value = L4_IRQ_F_LEVEL_LOW; break;
1.131 + case 1: *value = L4_IRQ_F_LEVEL_HIGH; break;
1.132 + case 2: *value = L4_IRQ_F_NEG_EDGE; break;
1.133 + default: case 3: *value = L4_IRQ_F_POS_EDGE; break;
1.134 + }
1.135 + return;
1.136 + }
1.137 +
1.138 + config_get(pin, Port_direction, &direction);
1.139 +
1.140 + *func = Hw::Gpio_chip::Function_gpio;
1.141 + *value = direction ? Output : Input;
1.142 +}
1.143 +
1.144 +void
1.145 +Gpio_jz4730_chip::_get_pin_value(unsigned pin, uint32_t reg_upper,
1.146 + uint32_t reg_lower, unsigned *value)
1.147 +{
1.148 + uint8_t pin_out;
1.149 +
1.150 + if (pin >= _nr_pins)
1.151 + throw -L4_EINVAL;
1.152 +
1.153 + uint32_t reg = _select_bank_for_pin(reg_upper, reg_lower, pin, &pin_out);
1.154 +
1.155 + *value = (_regs[reg] & (3 << (pin_out << 1))) >> (pin_out << 1);
1.156 +}
1.157 +
1.158 // Obtain an IRQ abstraction for a pin.
1.159
1.160 Hw::Gpio_irq_pin *
1.161 @@ -473,6 +541,11 @@
1.162 static_cast<Gpio_jz4730_chip *>(gpio)->config_get(pin, reg, value);
1.163 }
1.164
1.165 +void jz4730_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value)
1.166 +{
1.167 + static_cast<Gpio_jz4730_chip *>(gpio)->config_pad_get(pin, func, value);
1.168 +}
1.169 +
1.170 void jz4730_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues)
1.171 {
1.172 static_cast<Gpio_jz4730_chip *>(gpio)->multi_setup(*mask, mode, outvalues);