ch347_spi: Add simple `spispeed` parameter

Add a programmer parameter `spispeed` that accepts a frequency in kHz
like it's done for other drivers. The frequency will be rounded down
to the closest possible divisor setting.

Change-Id: Ifa05b95f723dba81bdcc7015dcdf557af5f2e0a8
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/flashrom-stable/+/73153
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nicholas Chin <nic.c3.14@gmail.com>
diff --git a/ch347_spi.c b/ch347_spi.c
index 55e08b9..98ae28e 100644
--- a/ch347_spi.c
+++ b/ch347_spi.c
@@ -261,6 +261,13 @@
 	.probe_opcode	= default_spi_probe_opcode,
 };
 
+static unsigned int ch347_div_to_khz(unsigned int div)
+{
+	/* divisor is a power of two starting from 2 for `div == 0` */
+	const unsigned int clk_khz = 120*1000;
+	return clk_khz / (1 << (div + 1));
+}
+
 /* Largely copied from ch341a_spi.c */
 static int ch347_spi_init(void)
 {
@@ -270,6 +277,28 @@
 		return 1;
 	}
 
+	unsigned int div = 3; /* Default to 7.5MHz */
+	char *const spispeed = extract_programmer_param("spispeed");
+	if (spispeed) {
+		char *endptr;
+		const unsigned long khz = strtoul(spispeed, &endptr, 10);
+		if (*endptr != '\0' || endptr == spispeed) {
+			msg_perr("Invalid `spispeed` argument, please provide the frequency in kHz.\n");
+			free(spispeed);
+			free(ch347_data);
+			return 1;
+		}
+		free(spispeed);
+
+		for (div = 0; div < 7; ++div) {
+			if (ch347_div_to_khz(div) <= khz)
+				break;
+		}
+		msg_pinfo("Using spispeed of %ukHz.\n", ch347_div_to_khz(div));
+	} else {
+		msg_pdbg("Using default spispeed of %ukHz.\n", ch347_div_to_khz(div));
+	}
+
 	int32_t ret = libusb_init(NULL);
 	if (ret < 0) {
 		msg_perr("Could not initialize libusb!\n");
@@ -326,8 +355,8 @@
 		(desc.bcdDevice >> 4) & 0x000F,
 		(desc.bcdDevice >> 0) & 0x000F);
 
-	/* TODO: add programmer cfg for things like CS pin and divisor */
-	if (ch347_spi_config(ch347_data, 2) < 0)
+	/* TODO: add programmer cfg for things like CS pin */
+	if (ch347_spi_config(ch347_data, div) < 0)
 		goto error_exit;
 
 	return register_spi_master(&spi_master_ch347_spi, ch347_data);