|  | @@ -60,6 +60,10 @@ static const char TAG[] = "gpio expander";
 | 
	
		
			
				|  |  |  static void   IRAM_ATTR intr_isr_handler(void* arg);
 | 
	
		
			
				|  |  |  static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static esp_err_t mpr121_init(gpio_exp_t* self);
 | 
	
		
			
				|  |  | +static uint32_t  mpr121_read(gpio_exp_t* self);
 | 
	
		
			
				|  |  | +static void      mpr121_write(gpio_exp_t* self);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void 	pca9535_set_direction(gpio_exp_t* self);
 | 
	
		
			
				|  |  |  static uint32_t pca9535_read(gpio_exp_t* self);
 | 
	
		
			
				|  |  |  static void 	pca9535_write(gpio_exp_t* self);
 | 
	
	
		
			
				|  | @@ -98,6 +102,11 @@ static const struct gpio_exp_model_s {
 | 
	
		
			
				|  |  |  	void      (*set_direction)(gpio_exp_t* self);
 | 
	
		
			
				|  |  |  	void      (*set_pull_mode)(gpio_exp_t* self);
 | 
	
		
			
				|  |  |  } registered[] = {
 | 
	
		
			
				|  |  | +	{ .model = "mpr121",
 | 
	
		
			
				|  |  | +	  .trigger = GPIO_INTR_LOW_LEVEL,
 | 
	
		
			
				|  |  | +	  .init = mpr121_init,
 | 
	
		
			
				|  |  | +	  .read = mpr121_read,
 | 
	
		
			
				|  |  | +	  .write = mpr121_write, },	
 | 
	
		
			
				|  |  |  	{ .model = "pca9535",
 | 
	
		
			
				|  |  |  	  .trigger = GPIO_INTR_LOW_LEVEL,
 | 
	
		
			
				|  |  |  	  .set_direction = pca9535_set_direction,
 | 
	
	
		
			
				|  | @@ -498,6 +507,111 @@ static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio) {
 | 
	
		
			
				|  |  |                                          DRIVERS                                       
 | 
	
		
			
				|  |  |  ****************************************************************************************/
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/****************************************************************************************
 | 
	
		
			
				|  |  | + * MPR121 family : init, direction, read and write
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static esp_err_t mpr121_init(gpio_exp_t* self) {
 | 
	
		
			
				|  |  | +	// soft reset the MPR121
 | 
	
		
			
				|  |  | +	esp_err_t err = i2c_write(self->phy.port, self->phy.addr, 0x80, 0x63, 1);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/*
 | 
	
		
			
				|  |  | +	  There is variance of default values between libraries:
 | 
	
		
			
				|  |  | +                  Reg     AN3944     Adafruit_MPR121  BareConductive/MPR121
 | 
	
		
			
				|  |  | +	      MHDR    0x2b    0x01       0x01             0x01
 | 
	
		
			
				|  |  | +	      NHDR    0x2c    0x01       0x01             0x01
 | 
	
		
			
				|  |  | +	      NCLR    0x2d    0x00       0x0e             0x10
 | 
	
		
			
				|  |  | +	      FDLR    0x2e    0x00       0x00             0x20
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	      MHDF    0x2f    0x01       0x01             0x01
 | 
	
		
			
				|  |  | +	      NHDF    0x30    0x01       0x05             0x01
 | 
	
		
			
				|  |  | +	      NCLF    0x31    0xff       0x01             0x10
 | 
	
		
			
				|  |  | +	      FDLF    0x32    0x20       0x00             0x20
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	      NHDT    0x33    ----       0x00             0x01
 | 
	
		
			
				|  |  | +	      NCLT    0x34    ----       0x00             0x10
 | 
	
		
			
				|  |  | +	      FDLT    0x35    ----       0x00             0xff
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	      DTR     0x5b    ----       0x00             0x11
 | 
	
		
			
				|  |  | +	      AFE1    0x5c    ----       0x10             0xff
 | 
	
		
			
				|  |  | +	      AFE2    0x5d    0x04       0x20             0x30
 | 
	
		
			
				|  |  | +	      ECR     0x5e    0x0c       ----             0xcc
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	      ACCR0   0x7b    0x0b       0x0b             0x00
 | 
	
		
			
				|  |  | +	      ACCR1   0x7c    ----       ----             0x00
 | 
	
		
			
				|  |  | +	      USL     0x7d    0x9c       0xc8             0x00
 | 
	
		
			
				|  |  | +	      LSL     0x7e    0x65       0xb4             0x00
 | 
	
		
			
				|  |  | +	      TL      0x7f    0x8c       0x82             0x00
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	  BareConductive MPR121 values used below.
 | 
	
		
			
				|  |  | +	*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x2b, 0x01, 1); // MHDR
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x2c, 0x01, 1); // NHDR
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x2d, 0x10, 1); // NCLR
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x2e, 0x20, 1); // FDLR
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x2f, 0x01, 1); // MHDF
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x30, 0x01, 1); // NHDF
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x31, 0x10, 1); // NCLF
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x32, 0x20, 1); // FDLF
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x33, 0x01, 1); // NHDT
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x34, 0x10, 1); // NCLT
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x35, 0xff, 1); // FDLT
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x5b, 0x11, 1); // DTR
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x5c, 0xff, 1); // AFE1
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x5d, 0x30, 1); // AFE2
 | 
	
		
			
				|  |  | +	                                                                 // ECR set last
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x7b, 0x00, 1); // ACCR0
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x7c, 0x00, 1); // ACCR1
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x7d, 0x00, 1); // USL
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x7e, 0x00, 1); // LSL
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x7f, 0x00, 1); // TL
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// Touch & Release thresholds
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x41, 0x28, 1); // ELE0 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x42, 0x14, 1); // ELE0 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x43, 0x28, 1); // ELE1 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x44, 0x14, 1); // ELE1 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x45, 0x28, 1); // ELE2 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x46, 0x14, 1); // ELE2 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x47, 0x28, 1); // ELE3 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x48, 0x14, 1); // ELE3 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x49, 0x28, 1); // ELE4 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x4a, 0x14, 1); // ELE4 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x4b, 0x28, 1); // ELE5 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x4c, 0x14, 1); // ELE5 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x4d, 0x28, 1); // ELE6 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x4e, 0x14, 1); // ELE6 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x4f, 0x28, 1); // ELE7 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x50, 0x14, 1); // ELE7 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x51, 0x28, 1); // ELE8 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x52, 0x14, 1); // ELE8 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x53, 0x28, 1); // ELE9 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x54, 0x14, 1); // ELE9 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x55, 0x28, 1); // ELE10 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x56, 0x14, 1); // ELE10 Release Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x57, 0x28, 1); // ELE11 Touch Threshold
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x58, 0x14, 1); // ELE11 Release Threshold
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// finally set to run mode with 12 electrodes enabled
 | 
	
		
			
				|  |  | +	err |= i2c_write(self->phy.port, self->phy.addr, 0x5e, 0xcc, 1); // ECR
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return err;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static uint32_t mpr121_read(gpio_exp_t* self) {
 | 
	
		
			
				|  |  | +	// only return the lower 12 bits of the pin status registers
 | 
	
		
			
				|  |  | +	return i2c_read(self->phy.port, self->phy.addr, 0x00, 2) & 0x0fff;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void mpr121_write(gpio_exp_t* self) {
 | 
	
		
			
				|  |  | +	ESP_LOGE(TAG, "MPR121 GPIO write not implemented");
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /****************************************************************************************
 | 
	
		
			
				|  |  |   * PCA9535 family : direction, read and write
 | 
	
		
			
				|  |  |   */
 |