18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * spi_eeprom.c
38c2ecf20Sopenharmony_ci * Copyright (C) 2000-2001 Toshiba Corporation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
68c2ecf20Sopenharmony_ci * terms of the GNU General Public License version 2. This program is
78c2ecf20Sopenharmony_ci * licensed "as is" without any warranty of any kind, whether express
88c2ecf20Sopenharmony_ci * or implied.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/export.h>
158c2ecf20Sopenharmony_ci#include <linux/device.h>
168c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
178c2ecf20Sopenharmony_ci#include <linux/spi/eeprom.h>
188c2ecf20Sopenharmony_ci#include <asm/txx9/spi.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define AT250X0_PAGE_SIZE	8
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/* register board information for at25 driver */
238c2ecf20Sopenharmony_ciint __init spi_eeprom_register(int busid, int chipid, int size)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct spi_board_info info = {
268c2ecf20Sopenharmony_ci		.modalias = "at25",
278c2ecf20Sopenharmony_ci		.max_speed_hz = 1500000,	/* 1.5Mbps */
288c2ecf20Sopenharmony_ci		.bus_num = busid,
298c2ecf20Sopenharmony_ci		.chip_select = chipid,
308c2ecf20Sopenharmony_ci		/* Mode 0: High-Active, Sample-Then-Shift */
318c2ecf20Sopenharmony_ci	};
328c2ecf20Sopenharmony_ci	struct spi_eeprom *eeprom;
338c2ecf20Sopenharmony_ci	eeprom = kzalloc(sizeof(*eeprom), GFP_KERNEL);
348c2ecf20Sopenharmony_ci	if (!eeprom)
358c2ecf20Sopenharmony_ci		return -ENOMEM;
368c2ecf20Sopenharmony_ci	strcpy(eeprom->name, "at250x0");
378c2ecf20Sopenharmony_ci	eeprom->byte_len = size;
388c2ecf20Sopenharmony_ci	eeprom->page_size = AT250X0_PAGE_SIZE;
398c2ecf20Sopenharmony_ci	eeprom->flags = EE_ADDR1;
408c2ecf20Sopenharmony_ci	info.platform_data = eeprom;
418c2ecf20Sopenharmony_ci	return spi_register_board_info(&info, 1);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* simple temporary spi driver to provide early access to seeprom. */
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic struct read_param {
478c2ecf20Sopenharmony_ci	int busid;
488c2ecf20Sopenharmony_ci	int chipid;
498c2ecf20Sopenharmony_ci	int address;
508c2ecf20Sopenharmony_ci	unsigned char *buf;
518c2ecf20Sopenharmony_ci	int len;
528c2ecf20Sopenharmony_ci} *read_param;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic int __init early_seeprom_probe(struct spi_device *spi)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	int stat = 0;
578c2ecf20Sopenharmony_ci	u8 cmd[2];
588c2ecf20Sopenharmony_ci	int len = read_param->len;
598c2ecf20Sopenharmony_ci	char *buf = read_param->buf;
608c2ecf20Sopenharmony_ci	int address = read_param->address;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	dev_info(&spi->dev, "spiclk %u KHz.\n",
638c2ecf20Sopenharmony_ci		 (spi->max_speed_hz + 500) / 1000);
648c2ecf20Sopenharmony_ci	if (read_param->busid != spi->master->bus_num ||
658c2ecf20Sopenharmony_ci	    read_param->chipid != spi->chip_select)
668c2ecf20Sopenharmony_ci		return -ENODEV;
678c2ecf20Sopenharmony_ci	while (len > 0) {
688c2ecf20Sopenharmony_ci		/* spi_write_then_read can only work with small chunk */
698c2ecf20Sopenharmony_ci		int c = len < AT250X0_PAGE_SIZE ? len : AT250X0_PAGE_SIZE;
708c2ecf20Sopenharmony_ci		cmd[0] = 0x03;	/* AT25_READ */
718c2ecf20Sopenharmony_ci		cmd[1] = address;
728c2ecf20Sopenharmony_ci		stat = spi_write_then_read(spi, cmd, sizeof(cmd), buf, c);
738c2ecf20Sopenharmony_ci		buf += c;
748c2ecf20Sopenharmony_ci		len -= c;
758c2ecf20Sopenharmony_ci		address += c;
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci	return stat;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic struct spi_driver early_seeprom_driver __initdata = {
818c2ecf20Sopenharmony_ci	.driver = {
828c2ecf20Sopenharmony_ci		.name	= "at25",
838c2ecf20Sopenharmony_ci	},
848c2ecf20Sopenharmony_ci	.probe	= early_seeprom_probe,
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ciint __init spi_eeprom_read(int busid, int chipid, int address,
888c2ecf20Sopenharmony_ci			   unsigned char *buf, int len)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	int ret;
918c2ecf20Sopenharmony_ci	struct read_param param = {
928c2ecf20Sopenharmony_ci		.busid = busid,
938c2ecf20Sopenharmony_ci		.chipid = chipid,
948c2ecf20Sopenharmony_ci		.address = address,
958c2ecf20Sopenharmony_ci		.buf = buf,
968c2ecf20Sopenharmony_ci		.len = len
978c2ecf20Sopenharmony_ci	};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	read_param = &param;
1008c2ecf20Sopenharmony_ci	ret = spi_register_driver(&early_seeprom_driver);
1018c2ecf20Sopenharmony_ci	if (!ret)
1028c2ecf20Sopenharmony_ci		spi_unregister_driver(&early_seeprom_driver);
1038c2ecf20Sopenharmony_ci	return ret;
1048c2ecf20Sopenharmony_ci}
105