|  | @@ -271,3 +271,124 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	unsigned sync_read = onenand_flags & ONENAND_FLAG_SYNCREAD;
 | 
	
		
			
				|  |  | +	unsigned sync_write = onenand_flags & ONENAND_FLAG_SYNCWRITE;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Configure GPMC for synchronous read */
 | 
	
		
			
				|  |  | +	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
 | 
	
		
			
				|  |  | +			  GPMC_CONFIG1_WRAPBURST_SUPP |
 | 
	
		
			
				|  |  | +			  GPMC_CONFIG1_READMULTIPLE_SUPP |
 | 
	
		
			
				|  |  | +			  (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) |
 | 
	
		
			
				|  |  | +			  (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
 | 
	
		
			
				|  |  | +			  (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
 | 
	
		
			
				|  |  | +			  GPMC_CONFIG1_PAGE_LEN(2) |
 | 
	
		
			
				|  |  | +			  (cpu_is_omap34xx() ? 0 :
 | 
	
		
			
				|  |  | +				(GPMC_CONFIG1_WAIT_READ_MON |
 | 
	
		
			
				|  |  | +				 GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
 | 
	
		
			
				|  |  | +			  GPMC_CONFIG1_DEVICESIZE_16 |
 | 
	
		
			
				|  |  | +			  GPMC_CONFIG1_DEVICETYPE_NOR |
 | 
	
		
			
				|  |  | +			  GPMC_CONFIG1_MUXADDDATA);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return gpmc_cs_set_timings(cs, t);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int omap2_onenand_setup_async(void __iomem *onenand_base)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct gpmc_timings t;
 | 
	
		
			
				|  |  | +	int ret;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	omap2_onenand_set_async_mode(onenand_base);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	t = omap2_onenand_calc_async_timings();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ret = gpmc_set_async_mode(gpmc_onenand_data->cs, &t);
 | 
	
		
			
				|  |  | +	if (IS_ERR_VALUE(ret))
 | 
	
		
			
				|  |  | +		return ret;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	omap2_onenand_set_async_mode(onenand_base);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int ret, freq = *freq_ptr;
 | 
	
		
			
				|  |  | +	struct gpmc_timings t;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!freq) {
 | 
	
		
			
				|  |  | +		/* Very first call freq is not known */
 | 
	
		
			
				|  |  | +		freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
 | 
	
		
			
				|  |  | +		set_onenand_cfg(onenand_base);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	t = omap2_onenand_calc_sync_timings(gpmc_onenand_data, freq);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ret = gpmc_set_sync_mode(gpmc_onenand_data->cs, &t);
 | 
	
		
			
				|  |  | +	if (IS_ERR_VALUE(ret))
 | 
	
		
			
				|  |  | +		return ret;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	set_onenand_cfg(onenand_base);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	*freq_ptr = freq;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct device *dev = &gpmc_onenand_device.dev;
 | 
	
		
			
				|  |  | +	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
 | 
	
		
			
				|  |  | +	int ret;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ret = omap2_onenand_setup_async(onenand_base);
 | 
	
		
			
				|  |  | +	if (ret) {
 | 
	
		
			
				|  |  | +		dev_err(dev, "unable to set to async mode\n");
 | 
	
		
			
				|  |  | +		return ret;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!(gpmc_onenand_data->flags & l))
 | 
	
		
			
				|  |  | +		return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ret = omap2_onenand_setup_sync(onenand_base, freq_ptr);
 | 
	
		
			
				|  |  | +	if (ret)
 | 
	
		
			
				|  |  | +		dev_err(dev, "unable to set to sync mode\n");
 | 
	
		
			
				|  |  | +	return ret;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int err;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	gpmc_onenand_data = _onenand_data;
 | 
	
		
			
				|  |  | +	gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
 | 
	
		
			
				|  |  | +	gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (cpu_is_omap24xx() &&
 | 
	
		
			
				|  |  | +			(gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) {
 | 
	
		
			
				|  |  | +		printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n");
 | 
	
		
			
				|  |  | +		gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE;
 | 
	
		
			
				|  |  | +		gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (cpu_is_omap34xx())
 | 
	
		
			
				|  |  | +		gpmc_onenand_data->flags |= ONENAND_IN_OMAP34XX;
 | 
	
		
			
				|  |  | +	else
 | 
	
		
			
				|  |  | +		gpmc_onenand_data->flags &= ~ONENAND_IN_OMAP34XX;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
 | 
	
		
			
				|  |  | +				(unsigned long *)&gpmc_onenand_resource.start);
 | 
	
		
			
				|  |  | +	if (err < 0) {
 | 
	
		
			
				|  |  | +		pr_err("%s: Cannot request GPMC CS\n", __func__);
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
 | 
	
		
			
				|  |  | +							ONENAND_IO_SIZE - 1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (platform_device_register(&gpmc_onenand_device) < 0) {
 | 
	
		
			
				|  |  | +		pr_err("%s: Unable to register OneNAND device\n", __func__);
 | 
	
		
			
				|  |  | +		gpmc_cs_free(gpmc_onenand_data->cs);
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 |