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); | 	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) | static void regmap_irq_sync_unlock(struct irq_data *data) | ||||||
| { | { | ||||||
| 	struct regmap_irq_chip_data *d = irq_data_get_irq_chip_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 + | 		reg = d->chip->mask_base + | ||||||
| 			(i * map->reg_stride * d->irq_reg_stride); | 			(i * map->reg_stride * d->irq_reg_stride); | ||||||
| 		if (d->chip->mask_invert) { | 		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]); | 					 d->mask_buf_def[i], ~d->mask_buf[i]); | ||||||
| 		} else if (d->chip->unmask_base) { | 		} else if (d->chip->unmask_base) { | ||||||
| 			/* set mask with mask_base register */ | 			/* 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]); | 					d->mask_buf_def[i], ~d->mask_buf[i]); | ||||||
| 			if (ret < 0) | 			if (ret < 0) | ||||||
| 				dev_err(d->map->dev, | 				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 - | 			unmask_offset = d->chip->unmask_base - | ||||||
| 							d->chip->mask_base; | 							d->chip->mask_base; | ||||||
| 			/* clear mask with unmask_base register */ | 			/* clear mask with unmask_base register */ | ||||||
| 			ret = regmap_update_bits(d->map, | 			ret = regmap_irq_update_bits(d, | ||||||
| 					reg + unmask_offset, | 					reg + unmask_offset, | ||||||
| 					d->mask_buf_def[i], | 					d->mask_buf_def[i], | ||||||
| 					d->mask_buf[i]); | 					d->mask_buf[i]); | ||||||
| 		} else { | 		} else { | ||||||
| 			ret = regmap_update_bits(d->map, reg, | 			ret = regmap_irq_update_bits(d, reg, | ||||||
| 					 d->mask_buf_def[i], d->mask_buf[i]); | 					 d->mask_buf_def[i], d->mask_buf[i]); | ||||||
| 		} | 		} | ||||||
| 		if (ret != 0) | 		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); | 			(i * map->reg_stride * d->irq_reg_stride); | ||||||
| 		if (d->wake_buf) { | 		if (d->wake_buf) { | ||||||
| 			if (d->chip->wake_invert) | 			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->mask_buf_def[i], | ||||||
| 							 ~d->wake_buf[i]); | 							 ~d->wake_buf[i]); | ||||||
| 			else | 			else | ||||||
| 				ret = regmap_update_bits(d->map, reg, | 				ret = regmap_irq_update_bits(d, reg, | ||||||
| 							 d->mask_buf_def[i], | 							 d->mask_buf_def[i], | ||||||
| 							 d->wake_buf[i]); | 							 d->wake_buf[i]); | ||||||
| 			if (ret != 0) | 			if (ret != 0) | ||||||
|  | @ -153,10 +163,10 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | ||||||
| 		reg = d->chip->type_base + | 		reg = d->chip->type_base + | ||||||
| 			(i * map->reg_stride * d->type_reg_stride); | 			(i * map->reg_stride * d->type_reg_stride); | ||||||
| 		if (d->chip->type_invert) | 		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]); | 				d->type_buf_def[i], ~d->type_buf[i]); | ||||||
| 		else | 		else | ||||||
| 			ret = regmap_update_bits(d->map, reg, | 			ret = regmap_irq_update_bits(d, reg, | ||||||
| 				d->type_buf_def[i], d->type_buf[i]); | 				d->type_buf_def[i], d->type_buf[i]); | ||||||
| 		if (ret != 0) | 		if (ret != 0) | ||||||
| 			dev_err(d->map->dev, "Failed to sync type in %x\n", | 			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 + | 		reg = chip->mask_base + | ||||||
| 			(i * map->reg_stride * d->irq_reg_stride); | 			(i * map->reg_stride * d->irq_reg_stride); | ||||||
| 		if (chip->mask_invert) | 		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]); | 					 d->mask_buf[i], ~d->mask_buf[i]); | ||||||
| 		else if (d->chip->unmask_base) { | 		else if (d->chip->unmask_base) { | ||||||
| 			unmask_offset = d->chip->unmask_base - | 			unmask_offset = d->chip->unmask_base - | ||||||
| 					d->chip->mask_base; | 					d->chip->mask_base; | ||||||
| 			ret = regmap_update_bits(d->map, | 			ret = regmap_irq_update_bits(d, | ||||||
| 					reg + unmask_offset, | 					reg + unmask_offset, | ||||||
| 					d->mask_buf[i], | 					d->mask_buf[i], | ||||||
| 					d->mask_buf[i]); | 					d->mask_buf[i]); | ||||||
| 		} else | 		} else | ||||||
| 			ret = regmap_update_bits(map, reg, | 			ret = regmap_irq_update_bits(d, reg, | ||||||
| 					 d->mask_buf[i], d->mask_buf[i]); | 					 d->mask_buf[i], d->mask_buf[i]); | ||||||
| 		if (ret != 0) { | 		if (ret != 0) { | ||||||
| 			dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", | 			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); | 				(i * map->reg_stride * d->irq_reg_stride); | ||||||
| 
 | 
 | ||||||
| 			if (chip->wake_invert) | 			if (chip->wake_invert) | ||||||
| 				ret = regmap_update_bits(map, reg, | 				ret = regmap_irq_update_bits(d, reg, | ||||||
| 							 d->mask_buf_def[i], | 							 d->mask_buf_def[i], | ||||||
| 							 0); | 							 0); | ||||||
| 			else | 			else | ||||||
| 				ret = regmap_update_bits(map, reg, | 				ret = regmap_irq_update_bits(d, reg, | ||||||
| 							 d->mask_buf_def[i], | 							 d->mask_buf_def[i], | ||||||
| 							 d->wake_buf[i]); | 							 d->wake_buf[i]); | ||||||
| 			if (ret != 0) { | 			if (ret != 0) { | ||||||
|  | @ -603,10 +613,10 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | ||||||
| 			reg = chip->type_base + | 			reg = chip->type_base + | ||||||
| 				(i * map->reg_stride * d->type_reg_stride); | 				(i * map->reg_stride * d->type_reg_stride); | ||||||
| 			if (chip->type_invert) | 			if (chip->type_invert) | ||||||
| 				ret = regmap_update_bits(map, reg, | 				ret = regmap_irq_update_bits(d, reg, | ||||||
| 					d->type_buf_def[i], 0xFF); | 					d->type_buf_def[i], 0xFF); | ||||||
| 			else | 			else | ||||||
| 				ret = regmap_update_bits(map, reg, | 				ret = regmap_irq_update_bits(d, reg, | ||||||
| 					d->type_buf_def[i], 0x0); | 					d->type_buf_def[i], 0x0); | ||||||
| 			if (ret != 0) { | 			if (ret != 0) { | ||||||
| 				dev_err(map->dev, | 				dev_err(map->dev, | ||||||
|  |  | ||||||
|  | @ -884,6 +884,7 @@ struct regmap_irq { | ||||||
|  * |  * | ||||||
|  * @status_base: Base status register address. |  * @status_base: Base status register address. | ||||||
|  * @mask_base:   Base mask 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 |  * @unmask_base:  Base unmask register address. for chips who have | ||||||
|  *                separate mask and unmask registers |  *                separate mask and unmask registers | ||||||
|  * @ack_base:    Base ack address. If zero then the chip is clear on read. |  * @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 wake_base; | ||||||
| 	unsigned int type_base; | 	unsigned int type_base; | ||||||
| 	unsigned int irq_reg_stride; | 	unsigned int irq_reg_stride; | ||||||
|  | 	bool mask_writeonly:1; | ||||||
| 	bool init_ack_masked:1; | 	bool init_ack_masked:1; | ||||||
| 	bool mask_invert:1; | 	bool mask_invert:1; | ||||||
| 	bool use_ack:1; | 	bool use_ack:1; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Michael Grzeschik
						Michael Grzeschik