170c048a2SRene Buergel /* 270c048a2SRene Buergel * EZ-USB specific functions used by some of the USB to Serial drivers. 370c048a2SRene Buergel * 470c048a2SRene Buergel * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) 570c048a2SRene Buergel * 670c048a2SRene Buergel * This program is free software; you can redistribute it and/or 770c048a2SRene Buergel * modify it under the terms of the GNU General Public License version 870c048a2SRene Buergel * 2 as published by the Free Software Foundation. 970c048a2SRene Buergel */ 1070c048a2SRene Buergel 1170c048a2SRene Buergel #include <linux/kernel.h> 1270c048a2SRene Buergel #include <linux/init.h> 1370c048a2SRene Buergel #include <linux/slab.h> 1470c048a2SRene Buergel #include <linux/module.h> 1570c048a2SRene Buergel #include <linux/usb.h> 1670c048a2SRene Buergel #include <linux/firmware.h> 1770c048a2SRene Buergel #include <linux/ihex.h> 18c30186e5SGreg Kroah-Hartman #include <linux/usb/ezusb.h> 1970c048a2SRene Buergel 2070c048a2SRene Buergel struct ezusb_fx_type { 2170c048a2SRene Buergel /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ 2270c048a2SRene Buergel unsigned short cpucs_reg; 2370c048a2SRene Buergel unsigned short max_internal_adress; 2470c048a2SRene Buergel }; 2570c048a2SRene Buergel 26c30186e5SGreg Kroah-Hartman static struct ezusb_fx_type ezusb_fx1 = { 2770c048a2SRene Buergel .cpucs_reg = 0x7F92, 2870c048a2SRene Buergel .max_internal_adress = 0x1B3F, 2970c048a2SRene Buergel }; 3070c048a2SRene Buergel 3170c048a2SRene Buergel /* Commands for writing to memory */ 3270c048a2SRene Buergel #define WRITE_INT_RAM 0xA0 3370c048a2SRene Buergel #define WRITE_EXT_RAM 0xA3 3470c048a2SRene Buergel 35c30186e5SGreg Kroah-Hartman static int ezusb_writememory(struct usb_device *dev, int address, 3670c048a2SRene Buergel unsigned char *data, int length, __u8 request) 3770c048a2SRene Buergel { 3870c048a2SRene Buergel int result; 3970c048a2SRene Buergel unsigned char *transfer_buffer; 4070c048a2SRene Buergel 4170c048a2SRene Buergel if (!dev) 4270c048a2SRene Buergel return -ENODEV; 4370c048a2SRene Buergel 4470c048a2SRene Buergel transfer_buffer = kmemdup(data, length, GFP_KERNEL); 4570c048a2SRene Buergel if (!transfer_buffer) { 4670c048a2SRene Buergel dev_err(&dev->dev, "%s - kmalloc(%d) failed.\n", 4770c048a2SRene Buergel __func__, length); 4870c048a2SRene Buergel return -ENOMEM; 4970c048a2SRene Buergel } 5070c048a2SRene Buergel result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, 5170c048a2SRene Buergel USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 5270c048a2SRene Buergel address, 0, transfer_buffer, length, 3000); 5370c048a2SRene Buergel 5470c048a2SRene Buergel kfree(transfer_buffer); 5570c048a2SRene Buergel return result; 5670c048a2SRene Buergel } 5770c048a2SRene Buergel 58c30186e5SGreg Kroah-Hartman static int ezusb_set_reset(struct usb_device *dev, unsigned short cpucs_reg, 5970c048a2SRene Buergel unsigned char reset_bit) 6070c048a2SRene Buergel { 6170c048a2SRene Buergel int response = ezusb_writememory(dev, cpucs_reg, &reset_bit, 1, WRITE_INT_RAM); 6270c048a2SRene Buergel if (response < 0) 6370c048a2SRene Buergel dev_err(&dev->dev, "%s-%d failed: %d\n", 6470c048a2SRene Buergel __func__, reset_bit, response); 6570c048a2SRene Buergel return response; 6670c048a2SRene Buergel } 6770c048a2SRene Buergel 6870c048a2SRene Buergel int ezusb_fx1_set_reset(struct usb_device *dev, unsigned char reset_bit) 6970c048a2SRene Buergel { 7070c048a2SRene Buergel return ezusb_set_reset(dev, ezusb_fx1.cpucs_reg, reset_bit); 7170c048a2SRene Buergel } 7270c048a2SRene Buergel EXPORT_SYMBOL_GPL(ezusb_fx1_set_reset); 7370c048a2SRene Buergel 7470c048a2SRene Buergel static int ezusb_ihex_firmware_download(struct usb_device *dev, 7570c048a2SRene Buergel struct ezusb_fx_type fx, 7670c048a2SRene Buergel const char *firmware_path) 7770c048a2SRene Buergel { 7870c048a2SRene Buergel int ret = -ENOENT; 7970c048a2SRene Buergel const struct firmware *firmware = NULL; 8070c048a2SRene Buergel const struct ihex_binrec *record; 8170c048a2SRene Buergel 8270c048a2SRene Buergel if (request_ihex_firmware(&firmware, firmware_path, 8370c048a2SRene Buergel &dev->dev)) { 8470c048a2SRene Buergel dev_err(&dev->dev, 8570c048a2SRene Buergel "%s - request \"%s\" failed\n", 8670c048a2SRene Buergel __func__, firmware_path); 8770c048a2SRene Buergel goto out; 8870c048a2SRene Buergel } 8970c048a2SRene Buergel 9070c048a2SRene Buergel ret = ezusb_set_reset(dev, fx.cpucs_reg, 0); 9170c048a2SRene Buergel if (ret < 0) 9270c048a2SRene Buergel goto out; 9370c048a2SRene Buergel 9470c048a2SRene Buergel record = (const struct ihex_binrec *)firmware->data; 9570c048a2SRene Buergel for (; record; record = ihex_next_binrec(record)) { 9670c048a2SRene Buergel if (be32_to_cpu(record->addr) > fx.max_internal_adress) { 9770c048a2SRene Buergel ret = ezusb_writememory(dev, be32_to_cpu(record->addr), 9870c048a2SRene Buergel (unsigned char *)record->data, 9970c048a2SRene Buergel be16_to_cpu(record->len), WRITE_EXT_RAM); 10070c048a2SRene Buergel if (ret < 0) { 10170c048a2SRene Buergel dev_err(&dev->dev, "%s - ezusb_writememory " 10270c048a2SRene Buergel "failed writing internal memory " 10370c048a2SRene Buergel "(%d %04X %p %d)\n", __func__, ret, 10470c048a2SRene Buergel be32_to_cpu(record->addr), record->data, 10570c048a2SRene Buergel be16_to_cpu(record->len)); 10670c048a2SRene Buergel goto out; 10770c048a2SRene Buergel } 10870c048a2SRene Buergel } 10970c048a2SRene Buergel } 11070c048a2SRene Buergel 11170c048a2SRene Buergel ret = ezusb_set_reset(dev, fx.cpucs_reg, 1); 11270c048a2SRene Buergel if (ret < 0) 11370c048a2SRene Buergel goto out; 11470c048a2SRene Buergel record = (const struct ihex_binrec *)firmware->data; 11570c048a2SRene Buergel for (; record; record = ihex_next_binrec(record)) { 11670c048a2SRene Buergel if (be32_to_cpu(record->addr) <= fx.max_internal_adress) { 11770c048a2SRene Buergel ret = ezusb_writememory(dev, be32_to_cpu(record->addr), 11870c048a2SRene Buergel (unsigned char *)record->data, 11970c048a2SRene Buergel be16_to_cpu(record->len), WRITE_INT_RAM); 12070c048a2SRene Buergel if (ret < 0) { 12170c048a2SRene Buergel dev_err(&dev->dev, "%s - ezusb_writememory " 12270c048a2SRene Buergel "failed writing external memory " 12370c048a2SRene Buergel "(%d %04X %p %d)\n", __func__, ret, 12470c048a2SRene Buergel be32_to_cpu(record->addr), record->data, 12570c048a2SRene Buergel be16_to_cpu(record->len)); 12670c048a2SRene Buergel goto out; 12770c048a2SRene Buergel } 12870c048a2SRene Buergel } 12970c048a2SRene Buergel } 13070c048a2SRene Buergel ret = ezusb_set_reset(dev, fx.cpucs_reg, 0); 13170c048a2SRene Buergel out: 13270c048a2SRene Buergel release_firmware(firmware); 13370c048a2SRene Buergel return ret; 13470c048a2SRene Buergel } 13570c048a2SRene Buergel 13670c048a2SRene Buergel int ezusb_fx1_ihex_firmware_download(struct usb_device *dev, 13770c048a2SRene Buergel const char *firmware_path) 13870c048a2SRene Buergel { 13970c048a2SRene Buergel return ezusb_ihex_firmware_download(dev, ezusb_fx1, firmware_path); 14070c048a2SRene Buergel } 14170c048a2SRene Buergel EXPORT_SYMBOL_GPL(ezusb_fx1_ihex_firmware_download); 14270c048a2SRene Buergel 143c30186e5SGreg Kroah-Hartman #if 0 144c30186e5SGreg Kroah-Hartman /* 145c30186e5SGreg Kroah-Hartman * Once someone one needs these fx2 functions, uncomment them 146c30186e5SGreg Kroah-Hartman * and add them to ezusb.h and all should be good. 147c30186e5SGreg Kroah-Hartman */ 148c30186e5SGreg Kroah-Hartman static struct ezusb_fx_type ezusb_fx2 = { 149c30186e5SGreg Kroah-Hartman .cpucs_reg = 0xE600, 150c30186e5SGreg Kroah-Hartman .max_internal_adress = 0x3FFF, 151c30186e5SGreg Kroah-Hartman }; 152c30186e5SGreg Kroah-Hartman 153c30186e5SGreg Kroah-Hartman int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit) 154c30186e5SGreg Kroah-Hartman { 155c30186e5SGreg Kroah-Hartman return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit); 156c30186e5SGreg Kroah-Hartman } 157c30186e5SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset); 158c30186e5SGreg Kroah-Hartman 15970c048a2SRene Buergel int ezusb_fx2_ihex_firmware_download(struct usb_device *dev, 16070c048a2SRene Buergel const char *firmware_path) 16170c048a2SRene Buergel { 16270c048a2SRene Buergel return ezusb_ihex_firmware_download(dev, ezusb_fx2, firmware_path); 16370c048a2SRene Buergel } 16470c048a2SRene Buergel EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download); 165c30186e5SGreg Kroah-Hartman #endif 166