Support setting the Dediprog SF100 SPI voltage

Add a generic voltage parameter parser.
Move tolower_string() from dummyflasher.c to flashrom.c to make it
available everywhere.

Corresponding to flashrom svn r1226.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Acked-by: Stefan Reinauer <stepan@coreboot.org>
diff --git a/dediprog.c b/dediprog.c
index cf4bd64..1889bfe 100644
--- a/dediprog.c
+++ b/dediprog.c
@@ -55,34 +55,35 @@
 
 //int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
 
-static int dediprog_set_spi_voltage(uint16_t voltage)
+static int dediprog_set_spi_voltage(int millivolt)
 {
 	int ret;
-	unsigned int mv;
+	uint16_t voltage_selector;
 
-	switch (voltage) {
-	case 0x0:
+	switch (millivolt) {
+	case 0:
 		/* Admittedly this one is an assumption. */
-		mv = 0;
+		voltage_selector = 0x0;
 		break;
-	case 0x12:
-		mv = 1800;
+	case 1800:
+		voltage_selector = 0x12;
 		break;
-	case 0x11:
-		mv = 2500;
+	case 2500:
+		voltage_selector = 0x11;
 		break;
-	case 0x10:
-		mv = 3500;
+	case 3500:
+		voltage_selector = 0x10;
 		break;
 	default:
-		msg_perr("Unknown voltage selector 0x%x! Aborting.\n", voltage);
+		msg_perr("Unknown voltage %i mV! Aborting.\n", millivolt);
 		return 1;
 	}
-	msg_pdbg("Setting SPI voltage to %u.%03u V\n", mv / 1000, mv % 1000);
+	msg_pdbg("Setting SPI voltage to %u.%03u V\n", millivolt / 1000,
+		 millivolt % 1000);
 
-	ret = usb_control_msg(dediprog_handle, 0x42, 0x9, voltage, 0xff, NULL, 0x0, DEFAULT_TIMEOUT);
+	ret = usb_control_msg(dediprog_handle, 0x42, 0x9, voltage_selector, 0xff, NULL, 0x0, DEFAULT_TIMEOUT);
 	if (ret != 0x0) {
-		msg_perr("Command Set SPI Voltage 0x%x failed!\n", voltage);
+		msg_perr("Command Set SPI Voltage 0x%x failed!\n", voltage_selector);
 		return 1;
 	}
 	return 0;
@@ -279,13 +280,74 @@
 }
 #endif
 
+static int parse_voltage(char *voltage)
+{
+	char *tmp = NULL;
+	int i;
+	int millivolt;
+	int fraction = 0;
+
+	if (!voltage || !strlen(voltage)) {
+		msg_perr("Empty voltage= specified.\n");
+		return -1;
+	}
+	millivolt = (int)strtol(voltage, &tmp, 0);
+	voltage = tmp;
+	/* Handle "," and "." as decimal point. Everything after it is assumed
+	 * to be in decimal notation.
+	 */
+	if ((*voltage == '.') || (*voltage == ',')) {
+		voltage++;
+		for (i = 0; i < 3; i++) {
+			fraction *= 10;
+			/* Don't advance if the current character is invalid,
+			 * but continue multiplying.
+			 */
+			if ((*voltage < '0') || (*voltage > '9'))
+				continue;
+			fraction += *voltage - '0';
+			voltage++;
+		}
+		/* Throw away remaining digits. */
+		voltage += strspn(voltage, "0123456789");
+	}
+	/* The remaining string must be empty or "mV" or "V". */
+	tolower_string(voltage);
+
+	/* No unit or "V". */
+	if ((*voltage == '\0') || !strncmp(voltage, "v", 1)) {
+		millivolt *= 1000;
+		millivolt += fraction;
+	} else if (!strncmp(voltage, "mv", 2) ||
+		   !strncmp(voltage, "milliv", 6)) {
+		/* No adjustment. fraction is discarded. */
+	} else {
+		/* Garbage at the end of the string. */
+		msg_perr("Garbage voltage= specified.\n");
+		return -1;
+	}
+	return millivolt;
+}
+
 /* URB numbers refer to the first log ever captured. */
 int dediprog_init(void)
 {
 	struct usb_device *dev;
+	char *voltage;
+	int millivolt = 3500;
 
 	msg_pspew("%s\n", __func__);
 
+	voltage = extract_programmer_param("voltage");
+	if (voltage) {
+		millivolt = parse_voltage(voltage);
+		free(voltage);
+		if (millivolt < 0) {
+			return 1;
+		}
+		msg_pinfo("Setting voltage to %i mV\n", millivolt);
+	}
+
 	/* Here comes the USB stuff. */
 	usb_init();
 	usb_find_busses();
@@ -315,7 +377,7 @@
 	if (dediprog_command_c())
 		return 1;
 	/* URB 11. Command Set SPI Voltage. */
-	if (dediprog_set_spi_voltage(0x10))
+	if (dediprog_set_spi_voltage(millivolt))
 		return 1;
 
 	buses_supported = CHIP_BUSTYPE_SPI;