drivers/pinctrl/freescale/pinctrl-imx1-core.c

Source file repositories/reference/linux-study-clean/drivers/pinctrl/freescale/pinctrl-imx1-core.c

File Facts

System
Linux kernel
Corpus path
drivers/pinctrl/freescale/pinctrl-imx1-core.c
Extension
.c
Size
17761 bytes
Lines
678
Domain
Driver Families
Bucket
drivers/pinctrl
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct imx1_pinctrl {
	struct device *dev;
	struct pinctrl_dev *pctl;
	void __iomem *base;
	const struct imx1_pinctrl_soc_info *info;
};

/*
 * MX1 register offsets
 */

#define MX1_DDIR 0x00
#define MX1_OCR 0x04
#define MX1_ICONFA 0x0c
#define MX1_ICONFB 0x14
#define MX1_GIUS 0x20
#define MX1_GPR 0x38
#define MX1_PUEN 0x40

#define MX1_PORT_STRIDE 0x100


/*
 * MUX_ID format defines
 */
#define MX1_MUX_FUNCTION(val) (BIT(0) & val)
#define MX1_MUX_GPIO(val) ((BIT(1) & val) >> 1)
#define MX1_MUX_DIR(val) ((BIT(2) & val) >> 2)
#define MX1_MUX_OCONF(val) (((BIT(4) | BIT(5)) & val) >> 4)
#define MX1_MUX_ICONFA(val) (((BIT(8) | BIT(9)) & val) >> 8)
#define MX1_MUX_ICONFB(val) (((BIT(10) | BIT(11)) & val) >> 10)


/*
 * IMX1 IOMUXC manages the pins based on ports. Each port has 32 pins. IOMUX
 * control registers are separated into function, output configuration, input
 * configuration A, input configuration B, GPIO in use and data direction.
 *
 * Those controls that are represented by 1 bit have a direct mapping between
 * bit position and pin id. If they are represented by 2 bit, the lower 16 pins
 * are in the first register and the upper 16 pins in the second (next)
 * register. pin_id is stored in bit (pin_id%16)*2 and the bit above.
 */

/*
 * Calculates the register offset from a pin_id
 */
static void __iomem *imx1_mem(struct imx1_pinctrl *ipctl, unsigned int pin_id)
{
	unsigned int port = pin_id / 32;
	return ipctl->base + port * MX1_PORT_STRIDE;
}

/*
 * Write to a register with 2 bits per pin. The function will automatically
 * use the next register if the pin is managed in the second register.
 */
static void imx1_write_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
		u32 value, u32 reg_offset)
{
	void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset;
	int offset = (pin_id % 16) * 2; /* offset, regardless of register used */
	int mask = ~(0x3 << offset); /* Mask for 2 bits at offset */
	u32 old_val;
	u32 new_val;

	/* Use the next register if the pin's port pin number is >=16 */
	if (pin_id % 32 >= 16)
		reg += 0x04;

	dev_dbg(ipctl->dev, "write: register 0x%p offset %d value 0x%x\n",
			reg, offset, value);

	/* Get current state of pins */
	old_val = readl(reg);
	old_val &= mask;

	new_val = value & 0x3; /* Make sure value is really 2 bit */
	new_val <<= offset;
	new_val |= old_val;/* Set new state for pin_id */

	writel(new_val, reg);
}

static void imx1_write_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id,
		u32 value, u32 reg_offset)
{
	void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset;
	int offset = pin_id % 32;
	int mask = ~BIT_MASK(offset);

Annotation

Implementation Notes