147 lines
		
	
	
	
		
			4.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			147 lines
		
	
	
	
		
			4.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * Generic PMC MSP71xx EXTENDED (EXD) GPIO handling. The extended gpio is | ||
|  |  * a set of hardware registers that have no need for explicit locking as | ||
|  |  * it is handled by unique method of writing individual set/clr bits. | ||
|  |  * | ||
|  |  * This program is free software; you can redistribute it and/or modify | ||
|  |  * it under the terms of the GNU General Public License version 2 as | ||
|  |  * published by the Free Software Foundation. | ||
|  |  * | ||
|  |  * @author Patrick Glass <patrickglass@gmail.com> | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <linux/kernel.h>
 | ||
|  | #include <linux/module.h>
 | ||
|  | #include <linux/init.h>
 | ||
|  | #include <linux/gpio.h>
 | ||
|  | #include <linux/io.h>
 | ||
|  | 
 | ||
|  | #define MSP71XX_DATA_OFFSET(gpio)	(2 * (gpio))
 | ||
|  | #define MSP71XX_READ_OFFSET(gpio)	(MSP71XX_DATA_OFFSET(gpio) + 1)
 | ||
|  | #define MSP71XX_CFG_OUT_OFFSET(gpio)	(MSP71XX_DATA_OFFSET(gpio) + 16)
 | ||
|  | #define MSP71XX_CFG_IN_OFFSET(gpio)	(MSP71XX_CFG_OUT_OFFSET(gpio) + 1)
 | ||
|  | 
 | ||
|  | #define MSP71XX_EXD_GPIO_BASE	0x0BC000000L
 | ||
|  | 
 | ||
|  | #define to_msp71xx_exd_gpio_chip(c) \
 | ||
|  | 			container_of(c, struct msp71xx_exd_gpio_chip, chip) | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * struct msp71xx_exd_gpio_chip - container for gpio chip and registers | ||
|  |  * @chip: chip structure for the specified gpio bank | ||
|  |  * @reg: register for control and data of gpio pin | ||
|  |  */ | ||
|  | struct msp71xx_exd_gpio_chip { | ||
|  | 	struct gpio_chip chip; | ||
|  | 	void __iomem *reg; | ||
|  | }; | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * msp71xx_exd_gpio_get() - return the chip's gpio value | ||
|  |  * @chip: chip structure which controls the specified gpio | ||
|  |  * @offset: gpio whose value will be returned | ||
|  |  * | ||
|  |  * It will return 0 if gpio value is low and other if high. | ||
|  |  */ | ||
|  | static int msp71xx_exd_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
|  | { | ||
|  | 	struct msp71xx_exd_gpio_chip *msp71xx_chip = | ||
|  | 	    to_msp71xx_exd_gpio_chip(chip); | ||
|  | 	const unsigned bit = MSP71XX_READ_OFFSET(offset); | ||
|  | 
 | ||
|  | 	return __raw_readl(msp71xx_chip->reg) & (1 << bit); | ||
|  | } | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * msp71xx_exd_gpio_set() - set the output value for the gpio | ||
|  |  * @chip: chip structure who controls the specified gpio | ||
|  |  * @offset: gpio whose value will be assigned | ||
|  |  * @value: logic level to assign to the gpio initially | ||
|  |  * | ||
|  |  * This will set the gpio bit specified to the desired value. It will set the | ||
|  |  * gpio pin low if value is 0 otherwise it will be high. | ||
|  |  */ | ||
|  | static void msp71xx_exd_gpio_set(struct gpio_chip *chip, | ||
|  | 				 unsigned offset, int value) | ||
|  | { | ||
|  | 	struct msp71xx_exd_gpio_chip *msp71xx_chip = | ||
|  | 	    to_msp71xx_exd_gpio_chip(chip); | ||
|  | 	const unsigned bit = MSP71XX_DATA_OFFSET(offset); | ||
|  | 
 | ||
|  | 	__raw_writel(1 << (bit + (value ? 1 : 0)), msp71xx_chip->reg); | ||
|  | } | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * msp71xx_exd_direction_output() - declare the direction mode for a gpio | ||
|  |  * @chip: chip structure which controls the specified gpio | ||
|  |  * @offset: gpio whose value will be assigned | ||
|  |  * @value: logic level to assign to the gpio initially | ||
|  |  * | ||
|  |  * This call will set the mode for the @gpio to output. It will set the | ||
|  |  * gpio pin low if value is 0 otherwise it will be high. | ||
|  |  */ | ||
|  | static int msp71xx_exd_direction_output(struct gpio_chip *chip, | ||
|  | 					unsigned offset, int value) | ||
|  | { | ||
|  | 	struct msp71xx_exd_gpio_chip *msp71xx_chip = | ||
|  | 	    to_msp71xx_exd_gpio_chip(chip); | ||
|  | 
 | ||
|  | 	msp71xx_exd_gpio_set(chip, offset, value); | ||
|  | 	__raw_writel(1 << MSP71XX_CFG_OUT_OFFSET(offset), msp71xx_chip->reg); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * msp71xx_exd_direction_input() - declare the direction mode for a gpio | ||
|  |  * @chip: chip structure which controls the specified gpio | ||
|  |  * @offset: gpio whose to which the value will be assigned | ||
|  |  * | ||
|  |  * This call will set the mode for the @gpio to input. | ||
|  |  */ | ||
|  | static int msp71xx_exd_direction_input(struct gpio_chip *chip, unsigned offset) | ||
|  | { | ||
|  | 	struct msp71xx_exd_gpio_chip *msp71xx_chip = | ||
|  | 	    to_msp71xx_exd_gpio_chip(chip); | ||
|  | 
 | ||
|  | 	__raw_writel(1 << MSP71XX_CFG_IN_OFFSET(offset), msp71xx_chip->reg); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | #define MSP71XX_EXD_GPIO_BANK(name, exd_reg, base_gpio, num_gpio) \
 | ||
|  | { \ | ||
|  | 	.chip = { \ | ||
|  | 		.label		  = name, \ | ||
|  | 		.direction_input  = msp71xx_exd_direction_input, \ | ||
|  | 		.direction_output = msp71xx_exd_direction_output, \ | ||
|  | 		.get		  = msp71xx_exd_gpio_get, \ | ||
|  | 		.set		  = msp71xx_exd_gpio_set, \ | ||
|  | 		.base		  = base_gpio, \ | ||
|  | 		.ngpio		  = num_gpio, \ | ||
|  | 	}, \ | ||
|  | 	.reg	= (void __iomem *)(MSP71XX_EXD_GPIO_BASE + exd_reg), \ | ||
|  | } | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * struct msp71xx_exd_gpio_banks[] - container array of gpio banks | ||
|  |  * @chip: chip structure for the specified gpio bank | ||
|  |  * @reg: register for reading and writing the gpio pin value | ||
|  |  * | ||
|  |  * This array structure defines the extended gpio banks for the | ||
|  |  * PMC MIPS Processor. We specify the bank name, the data/config | ||
|  |  * register,the base starting gpio number, and the number of | ||
|  |  * gpios exposed by the bank of gpios. | ||
|  |  */ | ||
|  | static struct msp71xx_exd_gpio_chip msp71xx_exd_gpio_banks[] = { | ||
|  | 
 | ||
|  | 	MSP71XX_EXD_GPIO_BANK("GPIO_23_16", 0x188, 16, 8), | ||
|  | 	MSP71XX_EXD_GPIO_BANK("GPIO_27_24", 0x18C, 24, 4), | ||
|  | }; | ||
|  | 
 | ||
|  | void __init msp71xx_init_gpio_extended(void) | ||
|  | { | ||
|  | 	int i; | ||
|  | 
 | ||
|  | 	for (i = 0; i < ARRAY_SIZE(msp71xx_exd_gpio_banks); i++) | ||
|  | 		gpiochip_add(&msp71xx_exd_gpio_banks[i].chip); | ||
|  | } |