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 = ¶m; 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