/* * Generic device tree based pinctrl driver for one register per pin * type pinmux controllers * * Copyright (C) 2012 Texas Instruments, Inc. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ #include <linux/init.h>#include <linux/module.h>#include <linux/io.h>#include <linux/platform_device.h>#include <linux/slab.h>#include <linux/err.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/irqchip/chained_irq.h>#include <linux/of.h>#include <linux/of_irq.h>#include <linux/seq_file.h> #include <linux/pinctrl/pinconf-generic.h>#include <linux/pinctrl/pinconf.h>#include <linux/pinctrl/pinctrl.h>#include <linux/pinctrl/pinmux.h> #include <linux/platform_data/pinctrl-single.h> #include "core.h"#include "devicetree.h"#include "pinconf.h"#include "pinmux.h" #define DRIVER_NAME "pinctrl-single"#define PCS_OFF_DISABLED ~0U /** * struct pcs_func_vals - mux function register offset and value pair * @reg: register virtual address * @val: register value * @mask: mask */struct pcs_func_vals { void __iomem *reg; unsigned val; unsigned mask;}; /** * struct pcs_conf_vals - pinconf parameter, pinconf register offset * and value, enable, disable, mask * @param: config parameter * @val: user input bits in the pinconf register * @enable: enable bits in the pinconf register * @disable: disable bits in the pinconf register * @mask: mask bits in the register value */struct pcs_conf_vals { enum pin_config_param param; unsigned val; unsigned enable; unsigned disable; unsigned mask;}; /** * struct pcs_conf_type - pinconf property name, pinconf param pair * @name: property name in DTS file * @param: config parameter */struct pcs_conf_type { const char *name; enum pin_config_param param;}; /** * struct pcs_function - pinctrl function * @name: pinctrl function name * @vals: register and vals array * @nvals: number of entries in vals array * @conf: array of pin configurations * @nconfs: number of pin configurations available * @node: list node */struct pcs_function { const char *name; struct pcs_func_vals *vals; unsigned nvals; struct pcs_conf_vals *conf; int nconfs; struct list_head node;}; /** * struct pcs_gpiofunc_range - pin ranges with same mux value of gpio function * @offset: offset base of pins * @npins: number pins with the same mux value of gpio function * @gpiofunc: mux value of gpio function * @node: list node */struct pcs_gpiofunc_range { unsigned offset; unsigned npins; unsigned gpiofunc; struct list_head node;}; /** * struct pcs_data - wrapper for data needed by pinctrl framework * @pa: pindesc array * @cur: index to current element * * REVISIT: We should be able to drop this eventually by adding * support for registering pins individually in the pinctrl * framework for those drivers that don't need a static array. */struct pcs_data { struct pinctrl_pin_desc *pa; int cur;}; /** * struct pcs_soc_data - SoC specific settings * @flags: initial SoC specific PCS_FEAT_xxx values * @irq: optional interrupt for the controller * @irq_enable_mask: optional SoC specific interrupt enable mask * @irq_status_mask: optional SoC specific interrupt status mask * @rearm: optional SoC specific wake-up rearm function */struct pcs_soc_data { unsigned flags; int irq; unsigned irq_enable_mask; unsigned irq_status_mask; void (*rearm)(void);}; /** * struct pcs_device - pinctrl device instance * @res: resources * @base: virtual address of the controller * @saved_vals: saved values for the controller * @size: size of the ioremapped area * @dev: device entry * @np: device tree node * @pctl: pin controller device * @flags: mask of PCS_FEAT_xxx values * @missing_nr_pinctrl_cells: for legacy binding, may go away * @socdata: soc specific data * @lock: spinlock for register access * @mutex: mutex protecting the lists * @width: bits per mux register * @fmask: function register mask * @fshift: function register shift * @foff: value to turn mux off * @fmax: max number of functions in fmask * @bits_per_mux: number of bits per mux * @bits_per_pin: number of bits per pin * @pins: physical pins on the SoC * @gpiofuncs: list of gpio functions * @irqs: list of interrupt registers * @chip: chip container for this instance * @domain: IRQ domain for this instance * @desc: pin controller descriptor * @read: register read function to use * @write: register write function to use */struct pcs_device { struct resource *res; void __iomem *base; void *saved_vals; unsigned size; struct device *dev; struct device_node *np; struct pinctrl_dev *pctl; unsigned flags;#define PCS_CONTEXT_LOSS_OFF (1 << 3)#define PCS_QUIRK_SHARED_IRQ (1 << 2)#define PCS_FEAT_IRQ (1 << 1)#define PCS_FEAT_PINCONF (1 << 0) struct property *missing_nr_pinctrl_cells; struct pcs_soc_data socdata; raw_spinlock_t lock; struct mutex mutex; unsigned width; unsigned fmask; unsigned fshift; unsigned foff; unsigned fmax; bool bits_per_mux; unsigned bits_per_pin; struct pcs_data pins; struct list_head gpiofuncs; struct list_head irqs; struct irq_chip chip; struct irq_domain *domain; struct pinctrl_desc desc; unsigned (*read)(void __iomem *reg); void (*write)(unsigned val, void __iomem *reg);}; #define PCS_QUIRK_HAS_SHARED_IRQ (pcs->flags & PCS_QUIRK_SHARED_IRQ)#define PCS_HAS_IRQ (pcs->flags & PCS_FEAT_IRQ)#define PCS_HAS_PINCONF (pcs->flags & PCS_FEAT_PINCONF) static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config);static int pcs_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned num_configs); static enum pin_config_param pcs_bias[] = { PIN_CONFIG_BIAS_PULL_DOWN, PIN_CONFIG_BIAS_PULL_UP,}; /* * This lock class tells lockdep that irqchip core that this single * pinctrl can be in a different category than its parents, so it won't * report false recursion. */static struct lock_class_key pcs_lock_class; /* Class for the IRQ request mutex */static struct lock_class_key pcs_request_class; /* * REVISIT: Reads and writes could eventually use regmap or something * generic. But at least on omaps, some mux registers are performance * critical as they may need to be remuxed every time before and after * idle. Adding tests for register access width for every read and * write like regmap is doing is not desired, and caching the registers * does not help in this case. */ static unsigned int pcs_readb(void __iomem *reg){ return readb(reg);} static unsigned int pcs_readw(void __iomem *reg){ return readw(reg);} static unsigned int pcs_readl(void __iomem *reg){ return readl(reg);} static void pcs_writeb(unsigned int val, void __iomem *reg){ writeb(val, reg);} static void pcs_writew(unsigned int val, void __iomem *reg){ writew(val, reg);} static void pcs_writel(unsigned int val, void __iomem *reg){ writel(val, reg);} static unsigned int pcs_pin_reg_offset_get(struct pcs_device *pcs, unsigned int pin){ unsigned int mux_bytes = pcs->width / BITS_PER_BYTE; if (pcs->bits_per_mux) { unsigned int pin_offset_bytes; pin_offset_bytes = (pcs->bits_per_pin * pin) / BITS_PER_BYTE; return (pin_offset_bytes / mux_bytes) * mux_bytes; } return pin * mux_bytes;} static unsigned int pcs_pin_shift_reg_get(struct pcs_device *pcs, unsigned int pin){ return (pin % (pcs->width / pcs->bits_per_pin)) * pcs->bits_per_pin;} static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin){ struct pcs_device *pcs; unsigned int val; unsigned long offset; size_t pa; pcs = pinctrl_dev_get_drvdata(pctldev); offset = pcs_pin_reg_offset_get(pcs, pin); val = pcs->read(pcs->base + offset); if (pcs->bits_per_mux) val &= pcs->fmask << pcs_pin_shift_reg_get(pcs, pin); pa = pcs->res->start + offset; seq_printf(s, "%zx %08x %s ", pa, val, DRIVER_NAME);} static void pcs_dt_free_map(struct pinctrl_dev *pctldev, struct pinctrl_map *map, unsigned num_maps){ struct pcs_device *pcs; pcs = pinctrl_dev_get_drvdata(pctldev); devm_kfree(pcs->dev, map);} static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps); static const struct pinctrl_ops pcs_pinctrl_ops = { .get_groups_count = pinctrl_generic_get_group_count, .get_group_name = pinctrl_generic_get_group_name, .get_group_pins = pinctrl_generic_get_group_pins, .pin_dbg_show = pcs_pin_dbg_show, .dt_node_to_map = pcs_dt_node_to_map, .dt_free_map = pcs_dt_free_map,}; static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin, struct pcs_function **func){ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pin_desc *pdesc = pin_desc_get(pctldev, pin); const struct pinctrl_setting_mux *setting; const struct function_desc *function; unsigned fselector; /* If pin is not described in DTS & enabled, mux_setting is NULL. */ setting = pdesc->mux_setting; if (!setting) return -ENOTSUPP; fselector = setting->func; function = pinmux_generic_get_function(pctldev, fselector); if (!function) return -EINVAL; *func = function->data; if (!(*func)) { dev_err(pcs->dev, "%s could not find function%i\n", __func__, fselector); return -ENOTSUPP; } return 0;} static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector, unsigned group){ struct pcs_device *pcs; const struct function_desc *function; struct pcs_function *func; int i; pcs = pinctrl_dev_get_drvdata(pctldev); /* If function mask is null, needn't enable it. */ if (!pcs->fmask) return 0; function = pinmux_generic_get_function(pctldev, fselector); if (!function) return -EINVAL; func = function->data; if (!func) return -EINVAL; dev_dbg(pcs->dev, "enabling %s function%i\n", func->name, fselector); for (i = 0; i < func->nvals; i++) { struct pcs_func_vals *vals; unsigned long flags; unsigned val, mask; vals = &func->vals[i]; raw_spin_lock_irqsave(&pcs->lock, flags); val = pcs->read(vals->reg); if (pcs->bits_per_mux) mask = vals->mask; else mask = pcs->fmask; val &= ~mask; val |= (vals->val & mask); pcs->write(val, vals->reg); raw_spin_unlock_irqrestore(&pcs->lock, flags); } return 0;} static int pcs_request_gpio(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned pin){ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pcs_gpiofunc_range *frange = NULL; struct list_head *pos, *tmp; unsigned data; /* If function mask is null, return directly. */ if (!pcs->fmask) return -ENOTSUPP; list_for_each_safe(pos, tmp, &pcs->gpiofuncs) { u32 offset; frange = list_entry(pos, struct pcs_gpiofunc_range, node); if (pin >= frange->offset + frange->npins || pin < frange->offset) continue; offset = pcs_pin_reg_offset_get(pcs, pin); if (pcs->bits_per_mux) { int pin_shift = pcs_pin_shift_reg_get(pcs, pin); data = pcs->read(pcs->base + offset); data &= ~(pcs->fmask << pin_shift); data |= frange->gpiofunc << pin_shift; pcs->write(data, pcs->base + offset); } else { data = pcs->read(pcs->base + offset); data &= ~pcs->fmask; data |= frange->gpiofunc; pcs->write(data, pcs->base + offset); } break; } return 0;} static const struct pinmux_ops pcs_pinmux_ops = { .get_functions_count = pinmux_generic_get_function_count, .get_function_name = pinmux_generic_get_function_name, .get_function_groups = pinmux_generic_get_function_groups, .set_mux = pcs_set_mux, .gpio_request_enable = pcs_request_gpio,}; /* Clear BIAS value */static void pcs_pinconf_clear_bias(struct pinctrl_dev *pctldev, unsigned pin){ unsigned long config; int i; for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) { config = pinconf_to_config_packed(pcs_bias[i], 0); pcs_pinconf_set(pctldev, pin, &config, 1); }} /* * Check whether PIN_CONFIG_BIAS_DISABLE is valid. * It's depend on that PULL_DOWN & PULL_UP configs are all invalid. */static bool pcs_pinconf_bias_disable(struct pinctrl_dev *pctldev, unsigned pin){ unsigned long config; int i; for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) { config = pinconf_to_config_packed(pcs_bias[i], 0); if (!pcs_pinconf_get(pctldev, pin, &config)) goto out; } return true;out: return false;} static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config){ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pcs_function *func; enum pin_config_param param; unsigned offset = 0, data = 0, i, j; int ret; ret = pcs_get_function(pctldev, pin, &func); if (ret) return ret; for (i = 0; i < func->nconfs; i++) { param = pinconf_to_config_param(*config); if (param == PIN_CONFIG_BIAS_DISABLE) { if (pcs_pinconf_bias_disable(pctldev, pin)) { *config = 0; return 0;Lines 1–500 of 2006. Load more
/* * Generic device tree based pinctrl driver for one register per pin * type pinmux controllers * * Copyright (C) 2012 Texas Instruments, Inc. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ #include <linux/init.h> #include <linux/module.h> #include <linux/io.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/list.h> #include <linux/interrupt.h> #include <linux/irqchip/chained_irq.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/seq_file.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> #include <linux/platform_data/pinctrl-single.h> #include "core.h" #include "devicetree.h" #include "pinconf.h" #include "pinmux.h" #define DRIVER_NAME "pinctrl-single" #define PCS_OFF_DISABLED ~0U /** * struct pcs_func_vals - mux function register offset and value pair * @reg: register virtual address * @val: register value * @mask: mask */ struct pcs_func_vals { void __iomem *reg; unsigned val; unsigned mask; }; /** * struct pcs_conf_vals - pinconf parameter, pinconf register offset * and value, enable, disable, mask * @param: config parameter * @val: user input bits in the pinconf register * @enable: enable bits in the pinconf register * @disable: disable bits in the pinconf register * @mask: mask bits in the register value */ struct pcs_conf_vals { enum pin_config_param param; unsigned val; unsigned enable; unsigned disable; unsigned mask; }; /** * struct pcs_conf_type - pinconf property name, pinconf param pair * @name: property name in DTS file * @param: config parameter */ struct pcs_conf_type { const char *name; enum pin_config_param param; }; /** * struct pcs_function - pinctrl function * @name: pinctrl function name * @vals: register and vals array * @nvals: number of entries in vals array * @conf: array of pin configurations * @nconfs: number of pin configurations available * @node: list node */ struct pcs_function { const char *name; struct pcs_func_vals *vals; unsigned nvals; struct pcs_conf_vals *conf; int nconfs; struct list_head node; }; /** * struct pcs_gpiofunc_range - pin ranges with same mux value of gpio function * @offset: offset base of pins * @npins: number pins with the same mux value of gpio function * @gpiofunc: mux value of gpio function * @node: list node */ struct pcs_gpiofunc_range { unsigned offset; unsigned npins; unsigned gpiofunc; struct list_head node; }; /** * struct pcs_data - wrapper for data needed by pinctrl framework * @pa: pindesc array * @cur: index to current element * * REVISIT: We should be able to drop this eventually by adding * support for registering pins individually in the pinctrl * framework for those drivers that don't need a static array. */ struct pcs_data { struct pinctrl_pin_desc *pa; int cur; }; /** * struct pcs_soc_data - SoC specific settings * @flags: initial SoC specific PCS_FEAT_xxx values * @irq: optional interrupt for the controller * @irq_enable_mask: optional SoC specific interrupt enable mask * @irq_status_mask: optional SoC specific interrupt status mask * @rearm: optional SoC specific wake-up rearm function */ struct pcs_soc_data { unsigned flags; int irq; unsigned irq_enable_mask; unsigned irq_status_mask; void (*rearm)(void); }; /** * struct pcs_device - pinctrl device instance * @res: resources * @base: virtual address of the controller * @saved_vals: saved values for the controller * @size: size of the ioremapped area * @dev: device entry * @np: device tree node * @pctl: pin controller device * @flags: mask of PCS_FEAT_xxx values * @missing_nr_pinctrl_cells: for legacy binding, may go away * @socdata: soc specific data * @lock: spinlock for register access * @mutex: mutex protecting the lists * @width: bits per mux register * @fmask: function register mask * @fshift: function register shift * @foff: value to turn mux off * @fmax: max number of functions in fmask * @bits_per_mux: number of bits per mux * @bits_per_pin: number of bits per pin * @pins: physical pins on the SoC * @gpiofuncs: list of gpio functions * @irqs: list of interrupt registers * @chip: chip container for this instance * @domain: IRQ domain for this instance * @desc: pin controller descriptor * @read: register read function to use * @write: register write function to use */ struct pcs_device { struct resource *res; void __iomem *base; void *saved_vals; unsigned size; struct device *dev; struct device_node *np; struct pinctrl_dev *pctl; unsigned flags; #define PCS_CONTEXT_LOSS_OFF (1 << 3) #define PCS_QUIRK_SHARED_IRQ (1 << 2) #define PCS_FEAT_IRQ (1 << 1) #define PCS_FEAT_PINCONF (1 << 0) struct property *missing_nr_pinctrl_cells; struct pcs_soc_data socdata; raw_spinlock_t lock; struct mutex mutex; unsigned width; unsigned fmask; unsigned fshift; unsigned foff; unsigned fmax; bool bits_per_mux; unsigned bits_per_pin; struct pcs_data pins; struct list_head gpiofuncs; struct list_head irqs; struct irq_chip chip; struct irq_domain *domain; struct pinctrl_desc desc; unsigned (*read)(void __iomem *reg); void (*write)(unsigned val, void __iomem *reg); }; #define PCS_QUIRK_HAS_SHARED_IRQ (pcs->flags & PCS_QUIRK_SHARED_IRQ) #define PCS_HAS_IRQ (pcs->flags & PCS_FEAT_IRQ) #define PCS_HAS_PINCONF (pcs->flags & PCS_FEAT_PINCONF) static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config); static int pcs_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned num_configs); static enum pin_config_param pcs_bias[] = { PIN_CONFIG_BIAS_PULL_DOWN, PIN_CONFIG_BIAS_PULL_UP, }; /* * This lock class tells lockdep that irqchip core that this single * pinctrl can be in a different category than its parents, so it won't * report false recursion. */ static struct lock_class_key pcs_lock_class; /* Class for the IRQ request mutex */ static struct lock_class_key pcs_request_class; /* * REVISIT: Reads and writes could eventually use regmap or something * generic. But at least on omaps, some mux registers are performance * critical as they may need to be remuxed every time before and after * idle. Adding tests for register access width for every read and * write like regmap is doing is not desired, and caching the registers * does not help in this case. */ static unsigned int pcs_readb(void __iomem *reg) { return readb(reg); } static unsigned int pcs_readw(void __iomem *reg) { return readw(reg); } static unsigned int pcs_readl(void __iomem *reg) { return readl(reg); } static void pcs_writeb(unsigned int val, void __iomem *reg) { writeb(val, reg); } static void pcs_writew(unsigned int val, void __iomem *reg) { writew(val, reg); } static void pcs_writel(unsigned int val, void __iomem *reg) { writel(val, reg); } static unsigned int pcs_pin_reg_offset_get(struct pcs_device *pcs, unsigned int pin) { unsigned int mux_bytes = pcs->width / BITS_PER_BYTE; if (pcs->bits_per_mux) { unsigned int pin_offset_bytes; pin_offset_bytes = (pcs->bits_per_pin * pin) / BITS_PER_BYTE; return (pin_offset_bytes / mux_bytes) * mux_bytes; } return pin * mux_bytes; } static unsigned int pcs_pin_shift_reg_get(struct pcs_device *pcs, unsigned int pin) { return (pin % (pcs->width / pcs->bits_per_pin)) * pcs->bits_per_pin; } static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin) { struct pcs_device *pcs; unsigned int val; unsigned long offset; size_t pa; pcs = pinctrl_dev_get_drvdata(pctldev); offset = pcs_pin_reg_offset_get(pcs, pin); val = pcs->read(pcs->base + offset); if (pcs->bits_per_mux) val &= pcs->fmask << pcs_pin_shift_reg_get(pcs, pin); pa = pcs->res->start + offset; seq_printf(s, "%zx %08x %s ", pa, val, DRIVER_NAME); } static void pcs_dt_free_map(struct pinctrl_dev *pctldev, struct pinctrl_map *map, unsigned num_maps) { struct pcs_device *pcs; pcs = pinctrl_dev_get_drvdata(pctldev); devm_kfree(pcs->dev, map); } static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps); static const struct pinctrl_ops pcs_pinctrl_ops = { .get_groups_count = pinctrl_generic_get_group_count, .get_group_name = pinctrl_generic_get_group_name, .get_group_pins = pinctrl_generic_get_group_pins, .pin_dbg_show = pcs_pin_dbg_show, .dt_node_to_map = pcs_dt_node_to_map, .dt_free_map = pcs_dt_free_map, }; static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin, struct pcs_function **func) { struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pin_desc *pdesc = pin_desc_get(pctldev, pin); const struct pinctrl_setting_mux *setting; const struct function_desc *function; unsigned fselector; /* If pin is not described in DTS & enabled, mux_setting is NULL. */ setting = pdesc->mux_setting; if (!setting) return -ENOTSUPP; fselector = setting->func; function = pinmux_generic_get_function(pctldev, fselector); if (!function) return -EINVAL; *func = function->data; if (!(*func)) { dev_err(pcs->dev, "%s could not find function%i\n", __func__, fselector); return -ENOTSUPP; } return 0; } static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector, unsigned group) { struct pcs_device *pcs; const struct function_desc *function; struct pcs_function *func; int i; pcs = pinctrl_dev_get_drvdata(pctldev); /* If function mask is null, needn't enable it. */ if (!pcs->fmask) return 0; function = pinmux_generic_get_function(pctldev, fselector); if (!function) return -EINVAL; func = function->data; if (!func) return -EINVAL; dev_dbg(pcs->dev, "enabling %s function%i\n", func->name, fselector); for (i = 0; i < func->nvals; i++) { struct pcs_func_vals *vals; unsigned long flags; unsigned val, mask; vals = &func->vals[i]; raw_spin_lock_irqsave(&pcs->lock, flags); val = pcs->read(vals->reg); if (pcs->bits_per_mux) mask = vals->mask; else mask = pcs->fmask; val &= ~mask; val |= (vals->val & mask); pcs->write(val, vals->reg); raw_spin_unlock_irqrestore(&pcs->lock, flags); } return 0; } static int pcs_request_gpio(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned pin) { struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pcs_gpiofunc_range *frange = NULL; struct list_head *pos, *tmp; unsigned data; /* If function mask is null, return directly. */ if (!pcs->fmask) return -ENOTSUPP; list_for_each_safe(pos, tmp, &pcs->gpiofuncs) { u32 offset; frange = list_entry(pos, struct pcs_gpiofunc_range, node); if (pin >= frange->offset + frange->npins || pin < frange->offset) continue; offset = pcs_pin_reg_offset_get(pcs, pin); if (pcs->bits_per_mux) { int pin_shift = pcs_pin_shift_reg_get(pcs, pin); data = pcs->read(pcs->base + offset); data &= ~(pcs->fmask << pin_shift); data |= frange->gpiofunc << pin_shift; pcs->write(data, pcs->base + offset); } else { data = pcs->read(pcs->base + offset); data &= ~pcs->fmask; data |= frange->gpiofunc; pcs->write(data, pcs->base + offset); } break; } return 0; } static const struct pinmux_ops pcs_pinmux_ops = { .get_functions_count = pinmux_generic_get_function_count, .get_function_name = pinmux_generic_get_function_name, .get_function_groups = pinmux_generic_get_function_groups, .set_mux = pcs_set_mux, .gpio_request_enable = pcs_request_gpio, }; /* Clear BIAS value */ static void pcs_pinconf_clear_bias(struct pinctrl_dev *pctldev, unsigned pin) { unsigned long config; int i; for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) { config = pinconf_to_config_packed(pcs_bias[i], 0); pcs_pinconf_set(pctldev, pin, &config, 1); } } /* * Check whether PIN_CONFIG_BIAS_DISABLE is valid. * It's depend on that PULL_DOWN & PULL_UP configs are all invalid. */ static bool pcs_pinconf_bias_disable(struct pinctrl_dev *pctldev, unsigned pin) { unsigned long config; int i; for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) { config = pinconf_to_config_packed(pcs_bias[i], 0); if (!pcs_pinconf_get(pctldev, pin, &config)) goto out; } return true; out: return false; } static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config) { struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pcs_function *func; enum pin_config_param param; unsigned offset = 0, data = 0, i, j; int ret; ret = pcs_get_function(pctldev, pin, &func); if (ret) return ret; for (i = 0; i < func->nconfs; i++) { param = pinconf_to_config_param(*config); if (param == PIN_CONFIG_BIAS_DISABLE) { if (pcs_pinconf_bias_disable(pctldev, pin)) { *config = 0; return 0;