From patchwork Wed Jun 13 09:01:57 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: Enable spi clock setting in dediprog driver Date: Wed, 13 Jun 2012 09:01:57 -0000 From: Nico Huber X-Patchwork-Id: 3656 Message-Id: <4FD85705.2040202@secunet.com> To: flashrom This adds a programmer parameter 'speed' in the dediprog driver to controll the transfer rate on the spi bus. The following rates are available (all in kHz): 24000, 12000, 8000, 3000, 2180, 1500, 750, 375 Signed-off-by: Nico Huber Index: dediprog.c =================================================================== --- dediprog.c (Revision 1541) +++ dediprog.c (Arbeitskopie) @@ -135,7 +144,6 @@ return 0; } -#if 0 /* After dediprog_set_spi_speed, the original app always calls * dediprog_set_spi_voltage(0) and then * dediprog_check_devicestring() four times in a row. @@ -149,43 +157,43 @@ * This looks suspiciously like the microprocessor in the SF100 has to be * restarted/reinitialized in case the speed changes. */ -static int dediprog_set_spi_speed(uint16_t speed) +static int dediprog_set_spi_speed(unsigned int khz) { int ret; - unsigned int khz; + uint16_t speed; /* Case 1 and 2 are in weird order. Probably an organically "grown" * interface. * Base frequency is 24000 kHz, divisors are (in order) * 1, 3, 2, 8, 11, 16, 32, 64. */ - switch (speed) { - case 0x0: - khz = 24000; + switch (khz) { + case 24000: + speed = 0; break; - case 0x1: - khz = 8000; + case 8000: + khz = 1; break; - case 0x2: - khz = 12000; + case 12000: + khz = 2; break; - case 0x3: - khz = 3000; + case 3000: + khz = 3; break; - case 0x4: - khz = 2180; + case 2180: + khz = 4; break; - case 0x5: - khz = 1500; + case 1500: + khz = 5; break; - case 0x6: - khz = 750; + case 750: + khz = 6; break; - case 0x7: - khz = 375; + case 375: + khz = 7; break; default: - msg_perr("Unknown frequency selector 0x%x! Aborting.\n", speed); + msg_perr("Unsupported frequency %d kHz! Aborting.\n", khz); return 1; } msg_pdbg("Setting SPI speed to %u kHz\n", khz); @@ -198,7 +206,6 @@ } return 0; } -#endif /* Bulk read interface, will read multiple 512 byte chunks aligned to 512 bytes. * @start start address @@ -701,6 +708,28 @@ return millivolt; } +static int dediprog_setup(void) +{ + /* URB 6. Command A. */ + if (dediprog_command_a()) { + return 1; + } + /* URB 7. Command A. */ + if (dediprog_command_a()) { + return 1; + } + /* URB 8. Command Prepare Receive Device String. */ + /* URB 9. Command Receive Device String. */ + if (dediprog_check_devicestring()) { + return 1; + } + /* URB 10. Command C. */ + if (dediprog_command_c()) { + return 1; + } + return 0; +} + static const struct spi_programmer spi_programmer_dediprog = { .type = SPI_CONTROLLER_DEDIPROG, .max_data_read = MAX_DATA_UNSPECIFIED, @@ -741,12 +770,18 @@ int dediprog_init(void) { struct usb_device *dev; - char *voltage; - int millivolt = 3500; + char *voltage, *speed; + int khz = 0, millivolt = 3500; int ret; msg_pspew("%s\n", __func__); + speed = extract_programmer_param("speed"); + if (speed) { + khz = strtol(speed, NULL, 0); + free(speed); + msg_pinfo("Setting speed to %i kHz\n", khz); + } voltage = extract_programmer_param("voltage"); if (voltage) { millivolt = parse_voltage(voltage); @@ -791,27 +843,25 @@ dediprog_set_leds(PASS_ON|BUSY_ON|ERROR_ON); - /* URB 6. Command A. */ - if (dediprog_command_a()) { + /* Perform basic setup. */ + if (dediprog_setup()) { dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); return 1; } - /* URB 7. Command A. */ - if (dediprog_command_a()) { - dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); - return 1; + + /* + * Set speed if requested. Set voltage to zero beforehand and setup + * again afterwards. Maybe we can skip the first setup. + */ + if (khz) { + if (dediprog_set_spi_voltage(0) || + dediprog_set_spi_speed(khz) || + dediprog_setup()) { + dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); + return 1; + } } - /* URB 8. Command Prepare Receive Device String. */ - /* URB 9. Command Receive Device String. */ - if (dediprog_check_devicestring()) { - dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); - return 1; - } - /* URB 10. Command C. */ - if (dediprog_command_c()) { - dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON); - return 1; - } + /* URB 11. Command Set SPI Voltage. */ if (dediprog_set_spi_voltage(millivolt)) { dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);