drivers: flash: add API to access SFDP region of serial flash devices

Some flash drivers are capable of issuing a JESD216 READ_SFDP command
to read serial flash discoverable parameters.  Allow applications and
utilities access to that capability where it's supported.

Signed-off-by: Peter A. Bigot <pab@pabigot.com>
diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in
index e140893..4490e7c 100644
--- a/doc/zephyr.doxyfile.in
+++ b/doc/zephyr.doxyfile.in
@@ -1969,6 +1969,7 @@
                          "CONFIG_DEVICE_IDLE_PM" \
                          "CONFIG_ERRNO" \
                          "CONFIG_EXECUTION_BENCHMARKING" \
+                         "CONFIG_FLASH_JESD216_API" \
                          "CONFIG_FLASH_PAGE_LAYOUT" \
                          "CONFIG_FPU" \
                          "CONFIG_FPU_SHARING" \
diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig
index 3c84fc1..20fcb29 100644
--- a/drivers/flash/Kconfig
+++ b/drivers/flash/Kconfig
@@ -23,6 +23,14 @@
 	 Selected by drivers that support JESD216-compatible flash
 	 devices to enable building a common support module.
 
+config FLASH_JESD216_API
+	bool "Provide API to read JESD216 flash parameters"
+	help
+	  This option extends the Zephyr flash API with the ability
+	  to access the Serial Flash Discoverable Parameter section
+	  allowing runtime determination of serial flash parameters
+	  for flash drivers that expose this capability.
+
 menuconfig FLASH
 	bool "Flash hardware support"
 	help
diff --git a/drivers/flash/flash_handlers.c b/drivers/flash/flash_handlers.c
index dde1768..a66ebde 100644
--- a/drivers/flash/flash_handlers.c
+++ b/drivers/flash/flash_handlers.c
@@ -72,4 +72,17 @@
 }
 #include <syscalls/flash_get_page_count_mrsh.c>
 
-#endif
+#endif /* CONFIG_FLASH_PAGE_LAYOUT */
+
+#ifdef CONFIG_FLASH_JESD216_API
+
+static inline int z_vrfy_flash_sfdp_read(struct device *dev, off_t offset,
+					 void *data, size_t len)
+{
+	Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, sfdp_read));
+	Z_OOPS(Z_SYSCALL_MEMORY_WRITE(data, len));
+	return z_impl_flash_sfdp_read(dev, offset, data, len);
+}
+#include <syscalls/flash_sfdp_read.c>
+
+#endif /* CONFIG_FLASH_JESD216_API */
diff --git a/include/drivers/flash.h b/include/drivers/flash.h
index 866987e..9cb6587 100644
--- a/include/drivers/flash.h
+++ b/include/drivers/flash.h
@@ -81,6 +81,9 @@
 				       size_t *layout_size);
 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
 
+typedef int (*flash_api_sfdp_read)(struct device *dev, off_t offset,
+				   void *data, size_t len);
+
 __subsystem struct flash_driver_api {
 	flash_api_read read;
 	flash_api_write write;
@@ -90,6 +93,9 @@
 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
 	flash_api_pages_layout page_layout;
 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
+#if defined(CONFIG_FLASH_JESD216_API)
+	flash_api_sfdp_read sfdp_read;
+#endif /* CONFIG_FLASH_JESD216_API */
 };
 
 /**
@@ -289,6 +295,44 @@
 void flash_page_foreach(struct device *dev, flash_page_cb cb, void *data);
 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
 
+#if defined(CONFIG_FLASH_JESD216_API)
+/**
+ * @brief Read data from Serial Flash Discoverable Parameters
+ *
+ * This routine reads data from a serial flash device compatible with
+ * the JEDEC JESD216 standard for encoding flash memory
+ * characteristics.
+ *
+ * Availability of this API is conditional on selecting
+ * @c CONFIG_FLASH_JESD216_API and support of that functionality in
+ * the driver underlying @p dev.
+ *
+ * @param dev device from which parameters will be read
+ * @param offset address within the SFDP region containing data of interest
+ * @param data where the data to be read will be placed
+ * @param len the number of bytes of data to be read
+ *
+ * @retval 0 on success
+ * @retval -ENOTSUP if the flash driver does not support SFDP access
+ * @retval negative values for other errors.
+ */
+__syscall int flash_sfdp_read(struct device *dev, off_t offset,
+			      void *data, size_t len);
+
+static inline int z_impl_flash_sfdp_read(struct device *dev, off_t offset,
+					 void *data, size_t len)
+{
+	int rv = -ENOTSUP;
+	const struct flash_driver_api *api =
+		(const struct flash_driver_api *)dev->api;
+
+	if (api->sfdp_read != NULL) {
+		rv = api->sfdp_read(dev, offset, data, len);
+	}
+	return rv;
+}
+#endif /* CONFIG_FLASH_JESD216_API */
+
 /**
  *  @brief  Get the minimum write block size supported by the driver
  *