|  | @@ -574,3 +574,185 @@ int gpmc_cs_configure(int cs, int cmd, int wval)
 | 
	
		
			
				|  |  |  		gpmc_write_reg(GPMC_IRQSTATUS, wval);
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	case GPMC_CONFIG_WP:
 | 
	
		
			
				|  |  | +		regval = gpmc_read_reg(GPMC_CONFIG);
 | 
	
		
			
				|  |  | +		if (wval)
 | 
	
		
			
				|  |  | +			regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
 | 
	
		
			
				|  |  | +		else
 | 
	
		
			
				|  |  | +			regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
 | 
	
		
			
				|  |  | +		gpmc_write_reg(GPMC_CONFIG, regval);
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	case GPMC_CONFIG_RDY_BSY:
 | 
	
		
			
				|  |  | +		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
 | 
	
		
			
				|  |  | +		if (wval)
 | 
	
		
			
				|  |  | +			regval |= WR_RD_PIN_MONITORING;
 | 
	
		
			
				|  |  | +		else
 | 
	
		
			
				|  |  | +			regval &= ~WR_RD_PIN_MONITORING;
 | 
	
		
			
				|  |  | +		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	case GPMC_CONFIG_DEV_SIZE:
 | 
	
		
			
				|  |  | +		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		/* clear 2 target bits */
 | 
	
		
			
				|  |  | +		regval &= ~GPMC_CONFIG1_DEVICESIZE(3);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		/* set the proper value */
 | 
	
		
			
				|  |  | +		regval |= GPMC_CONFIG1_DEVICESIZE(wval);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	case GPMC_CONFIG_DEV_TYPE:
 | 
	
		
			
				|  |  | +		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
 | 
	
		
			
				|  |  | +		regval |= GPMC_CONFIG1_DEVICETYPE(wval);
 | 
	
		
			
				|  |  | +		if (wval == GPMC_DEVICETYPE_NOR)
 | 
	
		
			
				|  |  | +			regval |= GPMC_CONFIG1_MUXADDDATA;
 | 
	
		
			
				|  |  | +		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
 | 
	
		
			
				|  |  | +		break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	default:
 | 
	
		
			
				|  |  | +		printk(KERN_ERR "gpmc_configure_cs: Not supported\n");
 | 
	
		
			
				|  |  | +		err = -EINVAL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return err;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +EXPORT_SYMBOL(gpmc_cs_configure);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	reg->gpmc_status = gpmc_base + GPMC_STATUS;
 | 
	
		
			
				|  |  | +	reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
 | 
	
		
			
				|  |  | +				GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
 | 
	
		
			
				|  |  | +	reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
 | 
	
		
			
				|  |  | +				GPMC_CS_NAND_ADDRESS + GPMC_CS_SIZE * cs;
 | 
	
		
			
				|  |  | +	reg->gpmc_nand_data = gpmc_base + GPMC_CS0_OFFSET +
 | 
	
		
			
				|  |  | +				GPMC_CS_NAND_DATA + GPMC_CS_SIZE * cs;
 | 
	
		
			
				|  |  | +	reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1;
 | 
	
		
			
				|  |  | +	reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2;
 | 
	
		
			
				|  |  | +	reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL;
 | 
	
		
			
				|  |  | +	reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS;
 | 
	
		
			
				|  |  | +	reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG;
 | 
	
		
			
				|  |  | +	reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL;
 | 
	
		
			
				|  |  | +	reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG;
 | 
	
		
			
				|  |  | +	reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (i = 0; i < GPMC_BCH_NUM_REMAINDER; i++) {
 | 
	
		
			
				|  |  | +		reg->gpmc_bch_result0[i] = gpmc_base + GPMC_ECC_BCH_RESULT_0 +
 | 
	
		
			
				|  |  | +					   GPMC_BCH_SIZE * i;
 | 
	
		
			
				|  |  | +		reg->gpmc_bch_result1[i] = gpmc_base + GPMC_ECC_BCH_RESULT_1 +
 | 
	
		
			
				|  |  | +					   GPMC_BCH_SIZE * i;
 | 
	
		
			
				|  |  | +		reg->gpmc_bch_result2[i] = gpmc_base + GPMC_ECC_BCH_RESULT_2 +
 | 
	
		
			
				|  |  | +					   GPMC_BCH_SIZE * i;
 | 
	
		
			
				|  |  | +		reg->gpmc_bch_result3[i] = gpmc_base + GPMC_ECC_BCH_RESULT_3 +
 | 
	
		
			
				|  |  | +					   GPMC_BCH_SIZE * i;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int gpmc_get_client_irq(unsigned irq_config)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (hweight32(irq_config) > 1)
 | 
	
		
			
				|  |  | +		return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (i = 0; i < GPMC_NR_IRQ; i++)
 | 
	
		
			
				|  |  | +		if (gpmc_client_irq[i].bitmask & irq_config)
 | 
	
		
			
				|  |  | +			return gpmc_client_irq[i].irq;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int gpmc_irq_endis(unsigned irq, bool endis)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +	u32 regval;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (i = 0; i < GPMC_NR_IRQ; i++)
 | 
	
		
			
				|  |  | +		if (irq == gpmc_client_irq[i].irq) {
 | 
	
		
			
				|  |  | +			regval = gpmc_read_reg(GPMC_IRQENABLE);
 | 
	
		
			
				|  |  | +			if (endis)
 | 
	
		
			
				|  |  | +				regval |= gpmc_client_irq[i].bitmask;
 | 
	
		
			
				|  |  | +			else
 | 
	
		
			
				|  |  | +				regval &= ~gpmc_client_irq[i].bitmask;
 | 
	
		
			
				|  |  | +			gpmc_write_reg(GPMC_IRQENABLE, regval);
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void gpmc_irq_disable(struct irq_data *p)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	gpmc_irq_endis(p->irq, false);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void gpmc_irq_enable(struct irq_data *p)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	gpmc_irq_endis(p->irq, true);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void gpmc_irq_noop(struct irq_data *data) { }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int gpmc_setup_irq(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +	u32 regval;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!gpmc_irq)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0);
 | 
	
		
			
				|  |  | +	if (IS_ERR_VALUE(gpmc_irq_start)) {
 | 
	
		
			
				|  |  | +		pr_err("irq_alloc_descs failed\n");
 | 
	
		
			
				|  |  | +		return gpmc_irq_start;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	gpmc_irq_chip.name = "gpmc";
 | 
	
		
			
				|  |  | +	gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret;
 | 
	
		
			
				|  |  | +	gpmc_irq_chip.irq_enable = gpmc_irq_enable;
 | 
	
		
			
				|  |  | +	gpmc_irq_chip.irq_disable = gpmc_irq_disable;
 | 
	
		
			
				|  |  | +	gpmc_irq_chip.irq_shutdown = gpmc_irq_noop;
 | 
	
		
			
				|  |  | +	gpmc_irq_chip.irq_ack = gpmc_irq_noop;
 | 
	
		
			
				|  |  | +	gpmc_irq_chip.irq_mask = gpmc_irq_noop;
 | 
	
		
			
				|  |  | +	gpmc_irq_chip.irq_unmask = gpmc_irq_noop;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE;
 | 
	
		
			
				|  |  | +	gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (i = 0; i < GPMC_NR_IRQ; i++) {
 | 
	
		
			
				|  |  | +		gpmc_client_irq[i].irq = gpmc_irq_start + i;
 | 
	
		
			
				|  |  | +		irq_set_chip_and_handler(gpmc_client_irq[i].irq,
 | 
	
		
			
				|  |  | +					&gpmc_irq_chip, handle_simple_irq);
 | 
	
		
			
				|  |  | +		set_irq_flags(gpmc_client_irq[i].irq,
 | 
	
		
			
				|  |  | +				IRQF_VALID | IRQF_NOAUTOEN);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Disable interrupts */
 | 
	
		
			
				|  |  | +	gpmc_write_reg(GPMC_IRQENABLE, 0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* clear interrupts */
 | 
	
		
			
				|  |  | +	regval = gpmc_read_reg(GPMC_IRQSTATUS);
 | 
	
		
			
				|  |  | +	gpmc_write_reg(GPMC_IRQSTATUS, regval);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int gpmc_free_irq(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (gpmc_irq)
 | 
	
		
			
				|  |  | +		free_irq(gpmc_irq, NULL);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (i = 0; i < GPMC_NR_IRQ; i++) {
 | 
	
		
			
				|  |  | +		irq_set_handler(gpmc_client_irq[i].irq, NULL);
 | 
	
		
			
				|  |  | +		irq_set_chip(gpmc_client_irq[i].irq, &no_irq_chip);
 | 
	
		
			
				|  |  | +		irq_modify_status(gpmc_client_irq[i].irq, 0, 0);
 | 
	
		
			
				|  |  | +	}
 |