*/
#define GPMC_NR_IRQ 2
+struct gpmc_cs_data {
+ const char *name;
+
+#define GPMC_CS_RESERVED (1 << 0)
+ u32 flags;
+
+ struct resource mem;
+};
+
struct gpmc_client_irq {
unsigned irq;
u32 bitmask;
static int gpmc_irq_start;
static struct resource gpmc_mem_root;
-static struct resource gpmc_cs_mem[GPMC_CS_NUM];
+static struct gpmc_cs_data gpmc_cs[GPMC_CS_NUM];
static DEFINE_SPINLOCK(gpmc_mem_lock);
/* Define chip-selects as reserved by default until probe completes */
-static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
static unsigned int gpmc_cs_num = GPMC_CS_NUM;
static unsigned int gpmc_nr_waitpins;
static struct device *gpmc_dev;
static void gpmc_cs_set_reserved(int cs, int reserved)
{
- gpmc_cs_map &= ~(1 << cs);
- gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+ gpmc->flags |= GPMC_CS_RESERVED;
}
static bool gpmc_cs_reserved(int cs)
{
- return gpmc_cs_map & (1 << cs);
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+ return gpmc->flags & GPMC_CS_RESERVED;
+}
+
+static void gpmc_cs_set_name(int cs, const char *name)
+{
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+ gpmc->name = name;
+}
+
+const char *gpmc_cs_get_name(int cs)
+{
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+ return gpmc->name;
}
static unsigned long gpmc_mem_align(unsigned long size)
static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
{
- struct resource *res = &gpmc_cs_mem[cs];
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+ struct resource *res = &gpmc->mem;
int r;
size = gpmc_mem_align(size);
static int gpmc_cs_delete_mem(int cs)
{
- struct resource *res = &gpmc_cs_mem[cs];
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+ struct resource *res = &gpmc->mem;
int r;
spin_lock(&gpmc_mem_lock);
int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
{
- struct resource *res = &gpmc_cs_mem[cs];
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+ struct resource *res = &gpmc->mem;
int r = -1;
if (cs > gpmc_cs_num) {
void gpmc_cs_free(int cs)
{
- struct resource *res = &gpmc_cs_mem[cs];
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+ struct resource *res = &gpmc->mem;
spin_lock(&gpmc_mem_lock);
if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
struct gpmc_timings gpmc_t;
struct resource res;
unsigned long base;
+ const char *name;
int ret, cs;
if (of_property_read_u32(child, "reg", &cs) < 0) {
return -ENODEV;
}
+ /*
+ * Check if we have multiple instances of the same device
+ * on a single chip select. If so, use the already initialized
+ * timings.
+ */
+ name = gpmc_cs_get_name(cs);
+ if (name && child->name && of_node_cmp(child->name, name) == 0)
+ goto no_timings;
+
ret = gpmc_cs_request(cs, resource_size(&res), &base);
if (ret < 0) {
dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
return ret;
}
+ gpmc_cs_set_name(cs, child->name);
/*
* For some GPMC devices we still need to rely on the bootloader
if (gpmc_setup_irq() < 0)
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
- /* Now the GPMC is initialised, unreserve the chip-selects */
- gpmc_cs_map = 0;
-
if (!pdev->dev.of_node) {
gpmc_cs_num = GPMC_CS_NUM;
gpmc_nr_waitpins = GPMC_NR_WAITPINS;