123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- From 8e5e628a9de439d02914b85a48e1ac3e04ea486a Mon Sep 17 00:00:00 2001
- From: Linus Walleij <[email protected]>
- Date: Thu, 11 Oct 2018 20:03:49 +0200
- Subject: [PATCH 06/18] mtd: physmap_of_gemini: Handle pin control
- This enables the complex mapping for the Gemini and kicks in
- custom read/write functions that will wrap the existing
- simple functions in calls to enable/disable the parallel
- flash pins using pin controls.
- This is necessary on some hardware such as the D-Link
- DIR-685 where all flash pins are patched in/out at the same
- time, but some of the flash pins are in practice unused by
- the flash and have anyway been reused as GPIO.
- This concerns specifically CE1 on the Gemini. There is only
- one flash chip, so only CE0 is used, and the line for CE1
- has been reused as chip select for the emulated SPI port
- connected to the display. If we try to use the same lines
- for flash and GPIO at the same time, one of them will loose:
- the GPIO line will disappear because it gets disconnected
- from the pin when the flash group is muxed out.
- Fix this by introducing two pin control states named simply
- "enabled" and "disabled" and only enable the flash lines
- when absolutely necessary (during read/write/copy). This
- way, they are available for GPIO at all other times and
- the display works.
- Collect all the state variables in a struct named
- struct gemini_flash and allocate this struct at probe
- time.
- Signed-off-by: Linus Walleij <[email protected]>
- ---
- drivers/mtd/maps/Kconfig | 1 +
- drivers/mtd/maps/physmap_of_gemini.c | 105 ++++++++++++++++++++++++++-
- 2 files changed, 105 insertions(+), 1 deletion(-)
- --- a/drivers/mtd/maps/Kconfig
- +++ b/drivers/mtd/maps/Kconfig
- @@ -89,6 +89,7 @@ config MTD_PHYSMAP_OF_GEMINI
- depends on MTD_PHYSMAP_OF
- depends on MFD_SYSCON
- default ARCH_GEMINI
- + select MTD_COMPLEX_MAPPINGS
- help
- This provides some extra DT physmap parsing for the Gemini
- platforms, some detection and setting up parallel mode on the
- --- a/drivers/mtd/maps/physmap_of_gemini.c
- +++ b/drivers/mtd/maps/physmap_of_gemini.c
- @@ -10,9 +10,11 @@
- #include <linux/of.h>
- #include <linux/of_device.h>
- #include <linux/mtd/map.h>
- +#include <linux/mtd/xip.h>
- #include <linux/mfd/syscon.h>
- #include <linux/regmap.h>
- #include <linux/bitops.h>
- +#include <linux/pinctrl/consumer.h>
- #include "physmap_of_gemini.h"
-
- /*
- @@ -49,6 +51,77 @@ static const struct of_device_id syscon_
- { },
- };
-
- +struct gemini_flash {
- + struct device *dev;
- + struct pinctrl *p;
- + struct pinctrl_state *enabled_state;
- + struct pinctrl_state *disabled_state;
- +};
- +
- +/* Static local state */
- +static struct gemini_flash *gf;
- +
- +static void gemini_flash_enable_pins(void)
- +{
- + int ret;
- +
- + if (IS_ERR(gf->enabled_state))
- + return;
- + ret = pinctrl_select_state(gf->p, gf->enabled_state);
- + if (ret)
- + dev_err(gf->dev, "failed to enable pins\n");
- +}
- +
- +static void gemini_flash_disable_pins(void)
- +{
- + int ret;
- +
- + if (IS_ERR(gf->disabled_state))
- + return;
- + ret = pinctrl_select_state(gf->p, gf->disabled_state);
- + if (ret)
- + dev_err(gf->dev, "failed to disable pins\n");
- +}
- +
- +static map_word __xipram gemini_flash_map_read(struct map_info *map,
- + unsigned long ofs)
- +{
- + map_word __xipram ret;
- +
- + gemini_flash_enable_pins();
- + ret = inline_map_read(map, ofs);
- + gemini_flash_disable_pins();
- +
- + return ret;
- +}
- +
- +static void __xipram gemini_flash_map_write(struct map_info *map,
- + const map_word datum,
- + unsigned long ofs)
- +{
- + gemini_flash_enable_pins();
- + inline_map_write(map, datum, ofs);
- + gemini_flash_disable_pins();
- +}
- +
- +static void __xipram gemini_flash_map_copy_from(struct map_info *map,
- + void *to, unsigned long from,
- + ssize_t len)
- +{
- + gemini_flash_enable_pins();
- + inline_map_copy_from(map, to, from, len);
- + gemini_flash_disable_pins();
- +}
- +
- +static void __xipram gemini_flash_map_copy_to(struct map_info *map,
- + unsigned long to,
- + const void *from, ssize_t len)
- +{
- + gemini_flash_enable_pins();
- + inline_map_copy_to(map, to, from, len);
- + gemini_flash_disable_pins();
- +}
- +
- int of_flash_probe_gemini(struct platform_device *pdev,
- struct device_node *np,
- struct map_info *map)
- @@ -62,6 +135,11 @@ int of_flash_probe_gemini(struct platfor
- if (!of_device_is_compatible(np, "cortina,gemini-flash"))
- return 0;
-
- + gf = devm_kzalloc(dev, sizeof(*gf), GFP_KERNEL);
- + if (!gf)
- + return -ENOMEM;
- + gf->dev = dev;
- +
- rmap = syscon_regmap_lookup_by_phandle(np, "syscon");
- if (IS_ERR(rmap)) {
- dev_err(dev, "no syscon\n");
- @@ -96,7 +174,32 @@ int of_flash_probe_gemini(struct platfor
- map->bankwidth * 8);
- }
-
- - dev_info(&pdev->dev, "initialized Gemini-specific physmap control\n");
- + gf->p = devm_pinctrl_get(dev);
- + if (IS_ERR(gf->p)) {
- + dev_err(dev, "no pinctrl handle\n");
- + ret = PTR_ERR(gf->p);
- + return ret;
- + }
- +
- + gf->enabled_state = pinctrl_lookup_state(gf->p, "enabled");
- + if (IS_ERR(gf->enabled_state))
- + dev_err(dev, "no enabled pin control state\n");
- +
- + gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled");
- + if (IS_ERR(gf->enabled_state)) {
- + dev_err(dev, "no disabled pin control state\n");
- + } else {
- + ret = pinctrl_select_state(gf->p, gf->disabled_state);
- + if (ret)
- + dev_err(gf->dev, "failed to disable pins\n");
- + }
- +
- + map->read = gemini_flash_map_read;
- + map->write = gemini_flash_map_write;
- + map->copy_from = gemini_flash_map_copy_from;
- + map->copy_to = gemini_flash_map_copy_to;
- +
- + dev_info(dev, "initialized Gemini-specific physmap control\n");
-
- return 0;
- }
|