forked from mirrors/linux
		
	regmap: irq: add chip option mask_writeonly
Some irq controllers have writeonly/multipurpose register layouts. In those cases we read invalid data back. Here we add the option mask_writeonly as masking option. Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
		
							parent
							
								
									63c73b059c
								
							
						
					
					
						commit
						a71411dbf6
					
				
					 2 changed files with 27 additions and 15 deletions
				
			
		|  | @ -60,6 +60,16 @@ static void regmap_irq_lock(struct irq_data *data) | |||
| 	mutex_lock(&d->lock); | ||||
| } | ||||
| 
 | ||||
| static int regmap_irq_update_bits(struct regmap_irq_chip_data *d, | ||||
| 				  unsigned int reg, unsigned int mask, | ||||
| 				  unsigned int val) | ||||
| { | ||||
| 	if (d->chip->mask_writeonly) | ||||
| 		return regmap_write_bits(d->map, reg, mask, val); | ||||
| 	else | ||||
| 		return regmap_update_bits(d->map, reg, mask, val); | ||||
| } | ||||
| 
 | ||||
| static void regmap_irq_sync_unlock(struct irq_data *data) | ||||
| { | ||||
| 	struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); | ||||
|  | @ -84,11 +94,11 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
| 		reg = d->chip->mask_base + | ||||
| 			(i * map->reg_stride * d->irq_reg_stride); | ||||
| 		if (d->chip->mask_invert) { | ||||
| 			ret = regmap_update_bits(d->map, reg, | ||||
| 			ret = regmap_irq_update_bits(d, reg, | ||||
| 					 d->mask_buf_def[i], ~d->mask_buf[i]); | ||||
| 		} else if (d->chip->unmask_base) { | ||||
| 			/* set mask with mask_base register */ | ||||
| 			ret = regmap_update_bits(d->map, reg, | ||||
| 			ret = regmap_irq_update_bits(d, reg, | ||||
| 					d->mask_buf_def[i], ~d->mask_buf[i]); | ||||
| 			if (ret < 0) | ||||
| 				dev_err(d->map->dev, | ||||
|  | @ -97,12 +107,12 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
| 			unmask_offset = d->chip->unmask_base - | ||||
| 							d->chip->mask_base; | ||||
| 			/* clear mask with unmask_base register */ | ||||
| 			ret = regmap_update_bits(d->map, | ||||
| 			ret = regmap_irq_update_bits(d, | ||||
| 					reg + unmask_offset, | ||||
| 					d->mask_buf_def[i], | ||||
| 					d->mask_buf[i]); | ||||
| 		} else { | ||||
| 			ret = regmap_update_bits(d->map, reg, | ||||
| 			ret = regmap_irq_update_bits(d, reg, | ||||
| 					 d->mask_buf_def[i], d->mask_buf[i]); | ||||
| 		} | ||||
| 		if (ret != 0) | ||||
|  | @ -113,11 +123,11 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
| 			(i * map->reg_stride * d->irq_reg_stride); | ||||
| 		if (d->wake_buf) { | ||||
| 			if (d->chip->wake_invert) | ||||
| 				ret = regmap_update_bits(d->map, reg, | ||||
| 				ret = regmap_irq_update_bits(d, reg, | ||||
| 							 d->mask_buf_def[i], | ||||
| 							 ~d->wake_buf[i]); | ||||
| 			else | ||||
| 				ret = regmap_update_bits(d->map, reg, | ||||
| 				ret = regmap_irq_update_bits(d, reg, | ||||
| 							 d->mask_buf_def[i], | ||||
| 							 d->wake_buf[i]); | ||||
| 			if (ret != 0) | ||||
|  | @ -153,10 +163,10 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
| 		reg = d->chip->type_base + | ||||
| 			(i * map->reg_stride * d->type_reg_stride); | ||||
| 		if (d->chip->type_invert) | ||||
| 			ret = regmap_update_bits(d->map, reg, | ||||
| 			ret = regmap_irq_update_bits(d, reg, | ||||
| 				d->type_buf_def[i], ~d->type_buf[i]); | ||||
| 		else | ||||
| 			ret = regmap_update_bits(d->map, reg, | ||||
| 			ret = regmap_irq_update_bits(d, reg, | ||||
| 				d->type_buf_def[i], d->type_buf[i]); | ||||
| 		if (ret != 0) | ||||
| 			dev_err(d->map->dev, "Failed to sync type in %x\n", | ||||
|  | @ -519,17 +529,17 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
| 		reg = chip->mask_base + | ||||
| 			(i * map->reg_stride * d->irq_reg_stride); | ||||
| 		if (chip->mask_invert) | ||||
| 			ret = regmap_update_bits(map, reg, | ||||
| 			ret = regmap_irq_update_bits(d, reg, | ||||
| 					 d->mask_buf[i], ~d->mask_buf[i]); | ||||
| 		else if (d->chip->unmask_base) { | ||||
| 			unmask_offset = d->chip->unmask_base - | ||||
| 					d->chip->mask_base; | ||||
| 			ret = regmap_update_bits(d->map, | ||||
| 			ret = regmap_irq_update_bits(d, | ||||
| 					reg + unmask_offset, | ||||
| 					d->mask_buf[i], | ||||
| 					d->mask_buf[i]); | ||||
| 		} else | ||||
| 			ret = regmap_update_bits(map, reg, | ||||
| 			ret = regmap_irq_update_bits(d, reg, | ||||
| 					 d->mask_buf[i], d->mask_buf[i]); | ||||
| 		if (ret != 0) { | ||||
| 			dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", | ||||
|  | @ -575,11 +585,11 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
| 				(i * map->reg_stride * d->irq_reg_stride); | ||||
| 
 | ||||
| 			if (chip->wake_invert) | ||||
| 				ret = regmap_update_bits(map, reg, | ||||
| 				ret = regmap_irq_update_bits(d, reg, | ||||
| 							 d->mask_buf_def[i], | ||||
| 							 0); | ||||
| 			else | ||||
| 				ret = regmap_update_bits(map, reg, | ||||
| 				ret = regmap_irq_update_bits(d, reg, | ||||
| 							 d->mask_buf_def[i], | ||||
| 							 d->wake_buf[i]); | ||||
| 			if (ret != 0) { | ||||
|  | @ -603,10 +613,10 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
| 			reg = chip->type_base + | ||||
| 				(i * map->reg_stride * d->type_reg_stride); | ||||
| 			if (chip->type_invert) | ||||
| 				ret = regmap_update_bits(map, reg, | ||||
| 				ret = regmap_irq_update_bits(d, reg, | ||||
| 					d->type_buf_def[i], 0xFF); | ||||
| 			else | ||||
| 				ret = regmap_update_bits(map, reg, | ||||
| 				ret = regmap_irq_update_bits(d, reg, | ||||
| 					d->type_buf_def[i], 0x0); | ||||
| 			if (ret != 0) { | ||||
| 				dev_err(map->dev, | ||||
|  |  | |||
|  | @ -884,6 +884,7 @@ struct regmap_irq { | |||
|  * | ||||
|  * @status_base: Base status register address. | ||||
|  * @mask_base:   Base mask register address. | ||||
|  * @mask_writeonly: Base mask register is write only. | ||||
|  * @unmask_base:  Base unmask register address. for chips who have | ||||
|  *                separate mask and unmask registers | ||||
|  * @ack_base:    Base ack address. If zero then the chip is clear on read. | ||||
|  | @ -927,6 +928,7 @@ struct regmap_irq_chip { | |||
| 	unsigned int wake_base; | ||||
| 	unsigned int type_base; | ||||
| 	unsigned int irq_reg_stride; | ||||
| 	bool mask_writeonly:1; | ||||
| 	bool init_ack_masked:1; | ||||
| 	bool mask_invert:1; | ||||
| 	bool use_ack:1; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Michael Grzeschik
						Michael Grzeschik