2026-01-29 22:25:33 +08:00

770 lines
20 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* zhaoxin pinctrl common code
*
* Copyright(c) 2021 Shanghai Zhaoxin Corporation. All rights reserved.
*
*/
#define DRIVER_VERSION "1.0.0"
#include <linux/acpi.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/time.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include "../core.h"
#include "pinctrl-zhaoxin.h"
static int pin_to_hwgpio(struct pinctrl_gpio_range *range, unsigned int pin)
{
int offset = 0;
if (range->pins) {
for (offset = 0; offset < range->npins; offset++)
if (pin == range->pins[offset])
break;
return range->base+offset-range->gc->base;
} else
return pin-range->pin_base+range->base-range->gc->base;
}
static u16 zx_pad_read16(struct zhaoxin_pinctrl *pctrl, u8 index)
{
outb(index, pctrl->pmio_rx90+pctrl->pmio_base);
return inw(pctrl->pmio_rx8c+pctrl->pmio_base);
}
static void zx_pad_write16(struct zhaoxin_pinctrl *pctrl, u8 index, u16 value)
{
outb(index, pctrl->pmio_rx90+pctrl->pmio_base);
outw(value, pctrl->pmio_rx8c+pctrl->pmio_base);
}
static int zhaoxin_get_groups_count(struct pinctrl_dev *pctldev)
{
struct zhaoxin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->soc->ngroups;
}
static const char *zhaoxin_get_group_name(struct pinctrl_dev *pctldev, unsigned int group)
{
struct zhaoxin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->soc->groups[group].name;
}
static int zhaoxin_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
const unsigned int **pins, unsigned int *npins)
{
struct zhaoxin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
*pins = pctrl->soc->groups[group].pins;
*npins = pctrl->soc->groups[group].npins;
return 0;
}
static void zhaoxin_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned int pin)
{
}
static const struct pinctrl_ops zhaoxin_pinctrl_ops = {
.get_groups_count = zhaoxin_get_groups_count,
.get_group_name = zhaoxin_get_group_name,
.get_group_pins = zhaoxin_get_group_pins,
.pin_dbg_show = zhaoxin_pin_dbg_show,
};
static int zhaoxin_get_functions_count(struct pinctrl_dev *pctldev)
{
struct zhaoxin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->soc->nfunctions;
}
static const char *zhaoxin_get_function_name(struct pinctrl_dev *pctldev, unsigned int function)
{
struct zhaoxin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->soc->functions[function].name;
}
static int zhaoxin_get_function_groups(struct pinctrl_dev *pctldev, unsigned int function,
const char * const **groups, unsigned int *const ngroups)
{
struct zhaoxin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
*groups = pctrl->soc->functions[function].groups;
*ngroups = pctrl->soc->functions[function].ngroups;
return 0;
}
static int zhaoxin_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
unsigned int group)
{
return 0;
}
#define ZHAOXIN_PULL_UP_20K 0x80
#define ZHAOXIN_PULL_UP_10K 0x40
#define ZHAOXIN_PULL_UP_47K 0x20
#define ZHAOXIN_PULL_DOWN 0x10
#define ZHAOXIN_PULL_UP 0xe0
static void zhaoxin_gpio_set_gpio_mode_and_pull(struct zhaoxin_pinctrl *pctrl, unsigned int pin,
bool isup)
{
u16 tmp = 0;
u16 value;
u16 value_back = 0;
if (isup)
tmp = ZHAOXIN_PULL_UP_10K|1;
else
tmp = ZHAOXIN_PULL_DOWN|1;
value = zx_pad_read16(pctrl, pin);
//for gpio
if (pin <= 0x32 && pin >= 0x29) {
if (isup) {
value &= (~(ZHAOXIN_PULL_DOWN));
value |= tmp;
} else {
value &= (~(ZHAOXIN_PULL_UP));
value |= tmp;
}
value &= ~(0x1);
zx_pad_write16(pctrl, pin, value);
value_back = zx_pad_read16(pctrl, pin);
} else {// for pgpio
if (isup) {
value &= (~(ZHAOXIN_PULL_DOWN));
value |= tmp;
} else {
value &= (~(ZHAOXIN_PULL_UP));
value |= tmp;
}
value |= 0x1;
zx_pad_write16(pctrl, pin, value);
value_back = zx_pad_read16(pctrl, pin);
}
}
static int zhaoxin_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range, unsigned int pin)
{
struct zhaoxin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
int hwgpio = pin_to_hwgpio(range, pin);
dev_dbg(pctrl->dev, "%s, hwgpio=%d, pin=%d\n", __func__, hwgpio, pin);
zhaoxin_gpio_set_gpio_mode_and_pull(pctrl, pin, true);
return 0;
}
static const struct pinmux_ops zhaoxin_pinmux_ops = {
.get_functions_count = zhaoxin_get_functions_count,
.get_function_name = zhaoxin_get_function_name,
.get_function_groups = zhaoxin_get_function_groups,
.set_mux = zhaoxin_pinmux_set_mux,
.gpio_request_enable = zhaoxin_gpio_request_enable,
};
static int zhaoxin_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config)
{
return 0;
}
static int zhaoxin_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *configs, unsigned int nconfigs)
{
return 0;
}
static const struct pinconf_ops zhaoxin_pinconf_ops = {
.is_generic = true,
.pin_config_get = zhaoxin_config_get,
.pin_config_set = zhaoxin_config_set,
};
static const struct pinctrl_desc zhaoxin_pinctrl_desc = {
.pctlops = &zhaoxin_pinctrl_ops,
.pmxops = &zhaoxin_pinmux_ops,
.confops = &zhaoxin_pinconf_ops,
.owner = THIS_MODULE,
};
static int zhaoxin_gpio_to_pin(struct zhaoxin_pinctrl *pctrl,
unsigned int offset,
const struct zhaoxin_pin_topology **community,
const struct zhaoxin_pin_map2_gpio **padgrp)
{
int i;
for (i = 0; i < pctrl->pin_map_size; i++) {
const struct zhaoxin_pin_map2_gpio *map = &pctrl->pin_maps[i];
if (map->zhaoxin_range_gpio_base == ZHAOXIN_GPIO_BASE_NOMAP)
continue;
if (offset >= map->zhaoxin_range_gpio_base &&
offset < map->zhaoxin_range_gpio_base + map->zhaoxin_range_pin_size) {
int pin;
pin = map->zhaoxin_range_pin_base + offset - map->zhaoxin_range_gpio_base;
if (padgrp)
*padgrp = map;
return pin;
}
}
return -EINVAL;
}
static __maybe_unused int zhaoxin_pin_to_gpio(
struct zhaoxin_pinctrl *pctrl, int pin)
{
const struct zhaoxin_pin_map2_gpio *pin_maps;
pin_maps = pctrl->pin_maps;
if (!pin_maps)
return -EINVAL;
return pin - pin_maps->zhaoxin_range_pin_base + pin_maps->zhaoxin_range_gpio_base;
}
static int zhaoxin_gpio_get(struct gpio_chip *chip,
unsigned int offset)
{
struct zhaoxin_pinctrl *pctrl = gpiochip_get_data(chip);
const struct index_cal_array *gpio_in_cal;
int gap = offset/16;
int bit = offset%16;
int pin;
int value;
gpio_in_cal = pctrl->pin_topologys->gpio_in_cal;
pin = zhaoxin_gpio_to_pin(pctrl, offset, NULL, NULL);
value = zx_pad_read16(pctrl, gpio_in_cal->index+gap);
value &= (1<<bit);
return !!value;
}
static void zhaoxin_gpio_set(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct zhaoxin_pinctrl *pctrl = gpiochip_get_data(chip);
const struct index_cal_array *gpio_out_cal;
unsigned long flags;
int gap = offset / 16;
int bit = offset % 16;
u16 org;
int pin;
gpio_out_cal = pctrl->pin_topologys->gpio_out_cal;
pin = zhaoxin_gpio_to_pin(pctrl, offset, NULL, NULL);
raw_spin_lock_irqsave(&pctrl->lock, flags);
org = zx_pad_read16(pctrl, gpio_out_cal->index+gap);
if (value)
org |= (1<<bit);
else
org &= (~(1<<bit));
zx_pad_write16(pctrl, gpio_out_cal->index+gap, org);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
}
static int zhaoxin_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
return pinctrl_gpio_direction_input(chip->base + offset);
}
static int zhaoxin_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value)
{
return pinctrl_gpio_direction_output(chip->base + offset);
}
static int zhaoxin_gpio_request(struct gpio_chip *gc, unsigned int offset)
{
return gpiochip_generic_request(gc, offset);
}
static void zhaoxin_gpio_free(struct gpio_chip *gc, unsigned int offset)
{
gpiochip_generic_free(gc, offset);
}
static int zhaoxin_gpio_config(struct gpio_chip *gc, unsigned int offset, unsigned long config)
{
return gpiochip_generic_config(gc, offset, config);
}
static const struct gpio_chip zhaoxin_gpio_chip = {
.owner = THIS_MODULE,
.request = zhaoxin_gpio_request,
.free = zhaoxin_gpio_free,
.direction_input = zhaoxin_gpio_direction_input,
.direction_output = zhaoxin_gpio_direction_output,
.get = zhaoxin_gpio_get,
.set = zhaoxin_gpio_set,
.set_config = zhaoxin_gpio_config,
};
static void zhaoxin_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct zhaoxin_pinctrl *pctrl = gpiochip_get_data(gc);
const struct reg_calibrate *status_cal;
const struct reg_cal_array *reg_off;
int gpio = irqd_to_hwirq(d);
int i, j;
int offset = 0;
int base_offset = 0;
int bit_off = 0;
u16 value;
u16 value_read;
status_cal = pctrl->pin_topologys->status_cal;
if (gpio >= 0) {
for (i = 0; i < status_cal->size; i++)
if (gpio == status_cal->cal_array[i])
break;
for (j = 0; j < status_cal->reg_cal_size; j++) {
if (offset > i)
break;
offset += status_cal->reg[j].size;
}
reg_off = &status_cal->reg[j-1];
bit_off = i-(offset-reg_off->size);
base_offset = reg_off->pmio_offset;
value = readw(pctrl->pm_pmio_base+reg_off->pmio_offset);
value_read = value;
value |= (1<<bit_off);
writew(value, pctrl->pm_pmio_base+reg_off->pmio_offset);
}
}
static void zhaoxin_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct zhaoxin_pinctrl *pctrl = gpiochip_get_data(gc);
const struct reg_calibrate *int_cal;
const struct reg_calibrate *mod_sel_cal;
int gpio = irqd_to_hwirq(d);
int i, j;
int offset = 0;
int base_offset = 0;
const struct reg_cal_array *reg_off, *mod;
int bit_off = 0;
u16 value;
u16 value1;
int_cal = pctrl->pin_topologys->int_cal;
mod_sel_cal = pctrl->pin_topologys->mod_sel_cal;
if (gpio >= 0) {
for (i = 0; i < int_cal->size; i++)
if (gpio == int_cal->cal_array[i])
break;
for (j = 0; j < int_cal->reg_cal_size; j++) {
if (offset > i)
break;
offset += int_cal->reg[j].size;
}
reg_off = &(int_cal->reg[j-1]);
mod = &(mod_sel_cal->reg[j-1]);
bit_off = i-(offset-reg_off->size);
base_offset = reg_off->pmio_offset;
value = inw(pctrl->pmio_base+reg_off->pmio_offset);
if (mask)
value &= (~(1<<bit_off));
else
value |= (1<<bit_off);
outw(value, pctrl->pmio_base+reg_off->pmio_offset);
if (mask) {
value1 = readw(pctrl->pm_pmio_base+mod->pmio_offset);
value1 |= (1<<bit_off);
writew(value1, pctrl->pm_pmio_base+mod->pmio_offset);
} else {
value1 = readw(pctrl->pm_pmio_base+mod->pmio_offset);
value1 |= (1<<bit_off);
writew(value1, pctrl->pm_pmio_base+mod->pmio_offset);
}
}
}
static void zhaoxin_gpio_irq_mask(struct irq_data *d)
{
zhaoxin_gpio_irq_mask_unmask(d, true);
}
static void zhaoxin_gpio_irq_unmask(struct irq_data *d)
{
zhaoxin_gpio_irq_mask_unmask(d, false);
}
/*
* father domain irq handle
*/
static irqreturn_t zhaoxin_gpio_irq(int irq, void *data)
{
struct zhaoxin_pinctrl *pctrl = data;
struct gpio_chip *gc = &pctrl->chip;
const struct reg_calibrate *init;
const struct reg_calibrate *stat_cal;
unsigned int i, bit_offset;
u16 status, enable;
unsigned long pending;
int index = 0;
int ret = 0;
int subirq;
unsigned int hwirq;
init = pctrl->pin_topologys->int_cal;
stat_cal = pctrl->pin_topologys->status_cal;
for (i = 0; i < init->reg_cal_size; i++) {
pending = 0;
status = readw(pctrl->pm_pmio_base + stat_cal->reg[i].pmio_offset);
enable = inw(pctrl->pmio_base + init->reg[i].pmio_offset);
enable &= status;
pending = enable;
for_each_set_bit(bit_offset, &pending, init->reg[i].size) {
hwirq = init->cal_array[index + bit_offset];
subirq = irq_find_mapping(gc->irq.domain, hwirq);
generic_handle_irq(subirq);
}
ret += pending ? 1 : 0;
index += init->reg[i].size;
}
return IRQ_RETVAL(ret);
}
static int zhaoxin_gpio_irq_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct zhaoxin_pinctrl *pctrl = gpiochip_get_data(gc);
unsigned int gpio = irqd_to_hwirq(d);
const struct index_cal_array *trigger_cal;
unsigned int pin;
unsigned long flags;
u8 index;
int position, point;
u16 value;
bool isup = true;
trigger_cal = pctrl->pin_topologys->trigger_cal;
pin = zhaoxin_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
if (type & IRQ_TYPE_EDGE_FALLING)
isup = true;
else if (type & IRQ_TYPE_EDGE_RISING)
isup = true;
else if (type & IRQ_TYPE_LEVEL_LOW)
isup = true;
else if (type & IRQ_TYPE_LEVEL_HIGH)
isup = false;
zhaoxin_gpio_set_gpio_mode_and_pull(pctrl, pin, isup);
for (position = 0; position < trigger_cal->size; position++)
if (trigger_cal->cal_array[position] == gpio)
break;
index = trigger_cal->index + ALIGN(position+1, 4)/4-1;
point = position % 4;
raw_spin_lock_irqsave(&pctrl->lock, flags);
value = zx_pad_read16(pctrl, index);
if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
value |= TRIGGER_BOTH_EDGE << (point*4);
else if (type & IRQ_TYPE_EDGE_FALLING)
value |= TRIGGER_FALL_EDGE << (point*4);
else if (type & IRQ_TYPE_EDGE_RISING)
value |= TRIGGER_RISE_EDGE << (point*4);
else if (type & IRQ_TYPE_LEVEL_LOW)
value |= TRIGGER_LOW_LEVEL << (point*4);
else if (type & IRQ_TYPE_LEVEL_HIGH)
value |= TRIGGER_HIGH_LEVEL << (point*4);
else
pr_debug("%s wrong type\n", __func__);
zx_pad_write16(pctrl, index, value);
if (type & IRQ_TYPE_EDGE_BOTH)
irq_set_handler_locked(d, handle_edge_irq);
else if (type & IRQ_TYPE_LEVEL_MASK)
irq_set_handler_locked(d, handle_level_irq);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
}
static int zhaoxin_gpio_irq_wake(struct irq_data *d, unsigned int on)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct zhaoxin_pinctrl *pctrl = gpiochip_get_data(gc);
unsigned int pin;
pin = zhaoxin_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
if (pin) {
if (on)
enable_irq_wake(pctrl->irq);
else
disable_irq_wake(pctrl->irq);
}
pr_debug("%s able wake for pin %u\n", on ? "en" : "dis", pin);
return 0;
}
static int zhaoxin_gpio_add_pin_ranges(struct gpio_chip *gc)
{
struct zhaoxin_pinctrl *pctrl = gpiochip_get_data(gc);
int ret, i;
for (i = 0; i < pctrl->pin_map_size; i++) {
struct zhaoxin_pin_map2_gpio *map = &pctrl->pin_maps[i];
if (map->zhaoxin_range_gpio_base == ZHAOXIN_GPIO_BASE_NOMAP)
continue;
ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev),
map->zhaoxin_range_gpio_base, map->zhaoxin_range_pin_base,
map->zhaoxin_range_pin_size);
if (ret) {
dev_err(pctrl->dev, "failed to add GPIO pin range\n");
return ret;
}
}
return 0;
}
static unsigned int zhaoxin_gpio_ngpio(const struct zhaoxin_pinctrl *pctrl)
{
const struct zhaoxin_pin_map2_gpio *pin_maps;
unsigned int ngpio = 0;
int i;
for (i = 0; i < pctrl->pin_map_size; i++) {
pin_maps = &pctrl->pin_maps[i];
if (pin_maps->zhaoxin_range_gpio_base == ZHAOXIN_GPIO_BASE_NOMAP)
continue;
if (pin_maps->zhaoxin_range_gpio_base + pin_maps->zhaoxin_range_pin_size > ngpio)
ngpio = pin_maps->zhaoxin_range_gpio_base +
pin_maps->zhaoxin_range_pin_size;
}
return ngpio;
}
static int zhaoxin_gpio_probe(struct zhaoxin_pinctrl *pctrl, int irq)
{
int ret;
struct gpio_irq_chip *girq;
pctrl->chip = zhaoxin_gpio_chip;
pctrl->chip.ngpio = zhaoxin_gpio_ngpio(pctrl);
pctrl->chip.label = dev_name(pctrl->dev);
pctrl->chip.parent = pctrl->dev;
pctrl->chip.base = -1;
pctrl->chip.add_pin_ranges = zhaoxin_gpio_add_pin_ranges;
pctrl->irq = irq;
pctrl->irqchip.name = dev_name(pctrl->dev);
pctrl->irqchip.irq_ack = zhaoxin_gpio_irq_ack;
pctrl->irqchip.irq_mask = zhaoxin_gpio_irq_mask;
pctrl->irqchip.irq_unmask = zhaoxin_gpio_irq_unmask;
pctrl->irqchip.irq_set_type = zhaoxin_gpio_irq_type;
pctrl->irqchip.irq_set_wake = zhaoxin_gpio_irq_wake;
pctrl->irqchip.flags = IRQCHIP_MASK_ON_SUSPEND;
/*
* father domain irq
*/
ret = devm_request_irq(pctrl->dev, irq, zhaoxin_gpio_irq,
IRQF_SHARED | IRQF_NO_THREAD,
dev_name(pctrl->dev), pctrl);
if (ret) {
dev_err(pctrl->dev, "failed to request interrupt\n");
return ret;
}
girq = &pctrl->chip.irq;
girq->chip = &pctrl->irqchip;
/* This will let us handle the IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl);
if (ret) {
dev_err(pctrl->dev, "failed to register gpiochip\n");
return ret;
}
return 0;
}
static int zhaoxin_pinctrl_pm_init(struct zhaoxin_pinctrl *pctrl)
{
return 0;
}
static int zhaoxin_pinctrl_probe(struct platform_device *pdev,
const struct zhaoxin_pinctrl_soc_data *soc_data)
{
struct zhaoxin_pinctrl *pctrl;
int ret, i, irq;
struct resource *res;
void __iomem *regs;
pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
if (!pctrl)
return -ENOMEM;
pctrl->dev = &pdev->dev;
pctrl->soc = soc_data;
raw_spin_lock_init(&pctrl->lock);
pctrl->pin_topologys = pctrl->soc->pin_topologys;
pctrl->pin_map_size = pctrl->soc->pin_map_size;
pctrl->pin_maps = devm_kcalloc(&pdev->dev, pctrl->pin_map_size,
sizeof(*pctrl->pin_maps), GFP_KERNEL);
if (!pctrl->pin_maps)
return -ENOMEM;
for (i = 0; i < pctrl->pin_map_size; i++) {
struct zhaoxin_pin_map2_gpio *community = &pctrl->pin_maps[i];
*community = pctrl->soc->zhaoxin_pin_maps[i];
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
pctrl->pm_pmio_base = regs;
pctrl->pmio_base = 0x800;
pctrl->pmio_rx90 = 0x90;
pctrl->pmio_rx8c = 0x8c;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = zhaoxin_pinctrl_pm_init(pctrl);
if (ret)
return ret;
pctrl->pctldesc = zhaoxin_pinctrl_desc;
pctrl->pctldesc.name = dev_name(&pdev->dev);
pctrl->pctldesc.pins = pctrl->soc->pins;
pctrl->pctldesc.npins = pctrl->soc->npins;
pctrl->pctldev = devm_pinctrl_register(&pdev->dev, &pctrl->pctldesc, pctrl);
if (IS_ERR(pctrl->pctldev)) {
dev_err(&pdev->dev, "failed to register pinctrl driver\n");
return PTR_ERR(pctrl->pctldev);
}
ret = zhaoxin_gpio_probe(pctrl, irq);
if (ret)
return ret;
platform_set_drvdata(pdev, pctrl);
return 0;
}
int zhaoxin_pinctrl_probe_by_hid(struct platform_device *pdev)
{
const struct zhaoxin_pinctrl_soc_data *data;
data = device_get_match_data(&pdev->dev);
if (!data)
return -ENODATA;
return zhaoxin_pinctrl_probe(pdev, data);
}
EXPORT_SYMBOL_GPL(zhaoxin_pinctrl_probe_by_hid);
int zhaoxin_pinctrl_probe_by_uid(struct platform_device *pdev)
{
const struct zhaoxin_pinctrl_soc_data *data;
data = zhaoxin_pinctrl_get_soc_data(pdev);
if (IS_ERR(data))
return PTR_ERR(data);
return zhaoxin_pinctrl_probe(pdev, data);
}
EXPORT_SYMBOL_GPL(zhaoxin_pinctrl_probe_by_uid);
const struct zhaoxin_pinctrl_soc_data *zhaoxin_pinctrl_get_soc_data(struct platform_device *pdev)
{
const struct zhaoxin_pinctrl_soc_data *data = NULL;
const struct zhaoxin_pinctrl_soc_data **table;
struct acpi_device *adev;
unsigned int i;
adev = ACPI_COMPANION(&pdev->dev);
if (adev) {
const void *match = device_get_match_data(&pdev->dev);
table = (const struct zhaoxin_pinctrl_soc_data **)match;
for (i = 0; table[i]; i++) {
if (!strcmp(adev->pnp.unique_id, table[i]->uid)) {
data = table[i];
break;
}
}
} else {
const struct platform_device_id *id;
id = platform_get_device_id(pdev);
if (!id)
return ERR_PTR(-ENODEV);
table = (const struct zhaoxin_pinctrl_soc_data **)id->driver_data;
data = table[pdev->id];
}
return data ?: ERR_PTR(-ENODATA);
}
EXPORT_SYMBOL_GPL(zhaoxin_pinctrl_get_soc_data);
#ifdef CONFIG_PM_SLEEP
int zhaoxin_pinctrl_suspend_noirq(struct device *dev)
{
/* TODO */
return 0;
}
EXPORT_SYMBOL_GPL(zhaoxin_pinctrl_suspend_noirq);
int zhaoxin_pinctrl_resume_noirq(struct device *dev)
{
/* TODO */
return 0;
}
EXPORT_SYMBOL_GPL(zhaoxin_pinctrl_resume_noirq);
#endif
MODULE_AUTHOR("www.zhaoxin.com");
MODULE_DESCRIPTION("Shanghai Zhaoxin pinctrl driver");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");