[PATCH 2/5] omap: mux: Add new style pin multiplexing code for omap3

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Initially only for 34xx. Keep the old code working
until the data has been converted to the new style
format.

REVISIT: Add support for cmdline parsing
REVISIT: Add a function to get mux register by GPIO pin
REVISIT: Add a function to set an array of mux entries

Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx>
---
 arch/arm/mach-omap2/mux.c |  237 +++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/mux.h |  125 ++++++++++++++++++++++++
 2 files changed, 362 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-omap2/mux.h

diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 9841423..45e6d4d 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -27,12 +27,15 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
+#include <linux/list.h>
 
 #include <asm/system.h>
 
 #include <plat/control.h>
 #include <plat/mux.h>
 
+#include "mux.h"
+
 #ifdef CONFIG_OMAP_MUX
 
 #define OMAP_MUX_BASE_OFFSET		0x30	/* Offset from CTRL_BASE */
@@ -626,6 +629,11 @@ static int __init_or_module omap24xx_cfg_reg(const struct pin_config *cfg)
 #endif
 
 #ifdef CONFIG_ARCH_OMAP34XX
+
+/*
+ * NOTE: This function will disappear soon, please use the new
+ * omap_mux_set() instead
+ */
 static int __init_or_module omap34xx_cfg_reg(const struct pin_config *cfg)
 {
 	static DEFINE_SPINLOCK(mux_spin_lock);
@@ -644,6 +652,235 @@ static int __init_or_module omap34xx_cfg_reg(const struct pin_config *cfg)
 #define omap34xx_cfg_reg	NULL
 #endif
 
+/*----------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP34XX
+
+static LIST_HEAD(muxmodes);
+static DEFINE_MUTEX(muxmode_mutex);
+
+/*
+ * REVISIT: See if pin is set dynamic, and add it to the list
+ */
+int omap_mux_set(u16 val, u16 mux_offset, int flags)
+{
+	omap_mux_write(val, mux_offset);
+
+	return 0;
+}
+
+struct omap_mux_entry {
+	struct omap_mux		mux;
+	struct list_head	node;
+};
+
+static struct omap_mux *omap_mux_list_add(struct omap_mux *src)
+{
+	struct omap_mux_entry *entry;
+	struct omap_mux *m;
+
+	int i;
+
+	entry = kzalloc(sizeof(struct omap_mux_entry), GFP_KERNEL);
+	if (!entry)
+		return NULL;
+
+	m = &entry->mux;
+	memcpy(m, src, sizeof(struct omap_mux_entry));
+
+#ifdef CONFIG_DEBUG_FS
+	for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
+		if (src->muxnames[i]) {
+			m->muxnames[i] =
+				kzalloc(strlen(src->muxnames[i]) + 1,
+					GFP_KERNEL);
+			if (!m->muxnames[i])
+				goto free_names;
+			strcpy(m->muxnames[i], src->muxnames[i]);
+		}
+	}
+	for (i = 0; i < OMAP_MUX_NR_SIDES; i++) {
+		if (src->balls[i]) {
+			m->balls[i] =
+				kzalloc(strlen(src->balls[i]) + 1,
+					GFP_KERNEL);
+			if (!m->balls[i])
+				goto free_balls;
+			strcpy(m->balls[i], src->balls[i]);
+		}
+	}
+#endif
+
+	mutex_lock(&muxmode_mutex);
+	list_add(&entry->node, &muxmodes);
+	mutex_unlock(&muxmode_mutex);
+
+	return m;
+
+#ifdef CONFIG_DEBUG_FS
+free_balls:
+	for (i = 0; i < OMAP_MUX_NR_SIDES; i++)
+		if (m->balls[i])
+			kfree(m->balls[i]);
+free_names:
+	for (i = 0; i < OMAP_MUX_NR_MODES; i++)
+		if (m->muxnames[i])
+			kfree(m->muxnames[i]);
+#endif
+
+	kfree(entry);
+
+	return NULL;
+}
+
+static void __init omap_mux_apply_subset(struct omap_mux *p,
+					struct omap_mux *superset)
+{
+	while (p->reg_offset !=  OMAP_MUX_TERMINATOR) {
+		struct omap_mux *s = superset;
+		int found = 0;
+
+		while (s->reg_offset != OMAP_MUX_TERMINATOR) {
+			if (s->reg_offset == p->reg_offset) {
+				*s = *p;
+				found++;
+				break;
+			}
+			s++;
+		}
+		if (!found)
+			printk(KERN_ERR "mux: Unknown entry offset 0x%x\n",
+					p->reg_offset);
+		p++;
+	}
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static void __init omap_mux_apply_pins(struct omap_ball *b,
+				struct omap_mux *superset)
+{
+	while (b->reg_offset != OMAP_MUX_TERMINATOR) {
+		struct omap_mux *s = superset;
+		int found = 0;
+
+		while (s->reg_offset != OMAP_MUX_TERMINATOR) {
+			if (s->reg_offset == b->reg_offset) {
+				s->balls[0] = b->balls[0];
+				s->balls[1] = b->balls[1];
+				found++;
+				break;
+			}
+			s++;
+		}
+		if (!found)
+			printk(KERN_ERR "mux: Unknown ball offset 0x%x\n",
+					b->reg_offset);
+		b++;
+	}
+}
+
+#else	/* CONFIG_DEBUG_FS */
+
+static inline void omap_mux_apply_pins(struct omap_ball *b,
+					struct omap_mux *superset)
+{
+}
+
+#endif	/* CONFIG_DEBUG_FS */
+
+static void __init omap_mux_set_board(struct omap_board_mux *board)
+{
+	while (board->reg_offset !=  OMAP_MUX_TERMINATOR) {
+		omap_mux_write(board->value, board->reg_offset);
+		board++;
+	}
+}
+
+static void __init omap_mux_init_dynamic(struct omap_board_mux *board_subset,
+					struct omap_mux *superset,
+					int flags)
+{
+	struct omap_mux *s = superset;
+	int always_dynamic = flags & OMAP_MUX_ALL_DYNAMIC;
+
+	while (s->reg_offset !=  OMAP_MUX_TERMINATOR) {
+		struct omap_mux *entry;
+
+		if (!always_dynamic) {
+			u16 mode;
+
+			/* GPIO pins must be always dynamic for PM */
+			mode = omap_mux_read(s->reg_offset) & 0x7;
+			if (mode != OMAP_MUX_MODE4)
+				continue;
+		}
+
+		entry = omap_mux_list_add(s);
+		if (!entry) {
+			printk(KERN_ERR "mux: Could not add entry\n");
+			return;
+		}
+		s++;
+	}
+
+	if (always_dynamic)
+		return;
+
+	/* Search for pins set as dynamic in the board-*.c file */
+	while (board_subset->reg_offset !=  OMAP_MUX_TERMINATOR) {
+
+		/* GPIO pins are always dynamic, and already handled */
+		if ((board_subset->value & 0x7) == OMAP_MUX_MODE4)
+			continue;
+
+		if (!(board_subset->flags & OMAP_MUX_DYNAMIC))
+			continue;
+
+		s = superset;
+		while (s->reg_offset !=  OMAP_MUX_TERMINATOR) {
+			if (s->reg_offset == board_subset->reg_offset) {
+				struct omap_mux *entry = omap_mux_list_add(s);
+				if (!entry) {
+					printk(KERN_ERR "mux: Could not add "
+						"board entry\n");
+					return;
+				}
+			}
+			s++;
+		}
+		board_subset++;
+	}
+}
+
+/*
+ * Do not call this from board-*.c files, use omap3_mux_init() instead
+ */
+int __init omap_mux_init(u32 mux_pbase, u32 mux_size,
+				struct omap_mux *superset,
+				struct omap_mux *package_subset,
+				struct omap_board_mux *board_subset,
+				struct omap_ball *package_balls,
+				int flags)
+{
+	/*
+	 * REVISIT: Do the ioremap with mux_pbase here once after the old
+	 * code is gone
+	 * REVISIT: Do not initialize again if already called
+	 */
+
+	omap_mux_apply_subset(package_subset, superset);
+	omap_mux_apply_pins(package_balls, superset);
+	omap_mux_set_board(board_subset);
+	omap_mux_init_dynamic(board_subset, superset, flags);
+
+	return 0;
+}
+
+#endif
+
+/*----------------------------------------------------------------------------*/
+
 int __init omap2_mux_init(void)
 {
 	u32 mux_pbase;
diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h
new file mode 100644
index 0000000..a8453f5
--- /dev/null
+++ b/arch/arm/mach-omap2/mux.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2009 Nokia
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * 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.
+ */
+
+#define OMAP_MUX_TERMINATOR	0xffff
+
+/* 34xx mux mode options for each pin. See TRM for options */
+#define OMAP_MUX_MODE0      0
+#define OMAP_MUX_MODE1      1
+#define OMAP_MUX_MODE2      2
+#define OMAP_MUX_MODE3      3
+#define OMAP_MUX_MODE4      4
+#define OMAP_MUX_MODE5      5
+#define OMAP_MUX_MODE6      6
+#define OMAP_MUX_MODE7      7
+
+/* 24xx/34xx mux bit defines */
+#define OMAP_PULL_ENA			(1 << 3)
+#define OMAP_PULL_UP			(1 << 4)
+#define OMAP_ALTELECTRICALSEL		(1 << 5)
+
+/* 34xx specific mux bit defines */
+#define OMAP_INPUT_EN			(1 << 8)
+#define OMAP_OFF_EN			(1 << 9)
+#define OMAP_OFFOUT_EN			(1 << 10)
+#define OMAP_OFFOUT_VAL			(1 << 11)
+#define OMAP_OFF_PULL_EN		(1 << 12)
+#define OMAP_OFF_PULL_UP		(1 << 13)
+#define OMAP_WAKEUP_EN			(1 << 14)
+
+/* Active pin states */
+#define OMAP_PIN_OUTPUT			0
+#define OMAP_PIN_INPUT			OMAP_INPUT_EN
+#define OMAP_PIN_INPUT_PULLUP		(OMAP_PULL_ENA | OMAP_INPUT_EN \
+						| OMAP_PULL_UP)
+#define OMAP_PIN_INPUT_PULLDOWN		(OMAP_PULL_ENA | OMAP_INPUT_EN)
+
+/* Off mode states */
+#define OMAP_PIN_OFF_NONE		0
+#define OMAP_PIN_OFF_OUTPUT_HIGH	(OMAP_OFF_EN | OMAP_OFFOUT_EN \
+						| OMAP_OFFOUT_VAL)
+#define OMAP_PIN_OFF_OUTPUT_LOW		(OMAP_OFF_EN | OMAP_OFFOUT_EN)
+#define OMAP_PIN_OFF_INPUT_PULLUP	(OMAP_OFF_EN | OMAP_OFF_PULL_EN \
+						| OMAP_OFF_PULL_UP)
+#define OMAP_PIN_OFF_INPUT_PULLDOWN	(OMAP_OFF_EN | OMAP_OFF_PULL_EN)
+#define OMAP_PIN_OFF_WAKEUPENABLE	OMAP_WAKEUP_EN
+
+/* Flags for struct omap_board_mux */
+#define OMAP_MUX_DYNAMIC		(1 << 0)	/* Keep mux in memory */
+
+/* Flags for omap_mux_init */
+#define OMAP_MUX_ALL_DYNAMIC		(1 << 16)	/* Always in memory */
+#define OMAP_PACKAGE_MASK		0xffff
+#define OMAP_PACKAGE_CUS		3		/* 423-pin 0.65 */
+#define OMAP_PACKAGE_CBB		2		/* 515-pin 0.40 0.50 */
+#define OMAP_PACKAGE_CBC		1		/* 515-pin 0.50 0.65 */
+
+
+#define OMAP_MUX_NR_MODES	8			/* Available modes */
+#define OMAP_MUX_NR_SIDES	2			/* Bottom & top */
+
+/**
+ * struct omap_mux - data for omap mux register offset and it's value
+ * @reg_offset:	mux register offset from the mux base
+ * @gpio:	GPIO number
+ * @muxnames:	available signal modes for a ball
+ */
+struct omap_mux {
+	u16	reg_offset;
+	u16	gpio;
+#ifdef CONFIG_DEBUG_FS
+	char	*muxnames[OMAP_MUX_NR_MODES];
+	char	*balls[OMAP_MUX_NR_SIDES];
+#endif
+};
+
+/**
+ * struct omap_ball - data for balls on omap package
+ * @reg_offset:	mux register offset from the mux base
+ * @balls:	available balls on the package
+ */
+struct omap_ball {
+	u16	reg_offset;
+	char	*balls[OMAP_MUX_NR_SIDES];
+};
+
+/**
+ * struct omap_board_mux - data for initializing mux registers
+ * @reg_offset:	mux register offset from the mux base
+ * @mux_value:	desired mux value to set
+ * @flags:	extra flags
+ */
+struct omap_board_mux {
+	u16	reg_offset;
+	u16	value;
+	u32	flags;
+};
+
+#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_ARCH_OMAP34XX)
+
+int omap3_mux_init(struct omap_board_mux *board_mux_config, int flags);
+int omap_mux_init(u32 mux_pbase, u32 mux_size,
+				struct omap_mux *superset,
+				struct omap_mux *package_subset,
+				struct omap_board_mux *board_subset,
+				struct omap_ball *package_balls,
+				int flags);
+int omap_mux_set(u16 val, u16 mux_offset, int flags);
+
+#else
+
+static inline int omap3_mux_init(struct omap_board_mux *board_mux_config,
+	int flags)
+{
+}
+static inline int omap_mux_set(u16 val, u16 mux_offset, int flags)
+{
+}
+
+#endif

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux