1
0
Fork 0

Bulk GPIO changes for the v5.3 kernel cycle:

Core:
 
 - When a gpio_chip request GPIOs from itself, it can now fully
   control the line characteristics, both machine and consumer
   flags. This makes a lot of sense, but took some time before I
   figured out that this is how it has to work.
 
 - Several smallish documentation fixes.
 
 New drivers:
 
 - The PCA953x driver now supports the TI TCA9539.
 
 - The DaVinci driver now supports the K3 AM654 SoCs.
 
 Driver improvements:
 
 - Major overhaul and hardening of the OMAP driver by Russell
   King.
 
 - Starting to move some drivers to the new API passing irq_chip
   along with the gpio_chip when adding the gpio_chip instead
   of adding it separately.
 
 Unrelated:
 
 - Delete the FMC subsystem.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEElDRnuGcz/wPCXQWMQRCzN7AZXXMFAl0i7gEACgkQQRCzN7AZ
 XXOeUA/+JKyI2zebTWBcgtxhn6VQCufMCtFmQl2JkEcy4pT7aBJcGWqFQCBW2Szf
 VTtqc8nNa90SZoOzsNbkeQgRjNKGZruMbh0ARUPcW4v3ZJHtUNUEDLTo8c3iyTgS
 9k/FTeaTLt4WSZujeAO0O7G4KNnOOlTKLh58dr0PmXUR+0v+fbMhcJqJ9ABueV+V
 qENdpkTuG1ZcvzgLhBBEXdt3Plw9ICLWmPXtwY+784ewucVPbyQX7jV4+bBZ25fL
 DerCuMIgL5vRWWdiFO6/Jp603rHzZpTnjLJJocXUFiD6zA5rvU2jTWxsnUttjisg
 8cTLMyQspsDvBxhEhCJVTuIKotbKH900TSaz+vx20W72/A1euy4y6uVi8FGZo4Ww
 KDkzB7anwHyEFKGnlYgHzDrfctgZrhQoyFz808DQRYg1JseZB5oGVDvScrPBD43j
 nbNDd8gwG4yp3tFnDx9xjIwQy3Ax4d510rAZyUN2801IlbA1bueq4t6Z2cCucWzX
 XA1gCKlXe4BUeitRAoZtqZNZG1ymEysW4jXy1V8xrwtAf8+QSN+xO98akz3VpnQL
 ae9q+HtF76fDBY1xFSXT37Ma3+4OR2vMF9QWuo4TCb9j1cL7llf8ZxtUq9LEHbDu
 erKLSSnwSFmqJNGSEA5SulGOCR/tRPkClngE9x0XEM6gOD+bs6E=
 =8zSV
 -----END PGP SIGNATURE-----

Merge tag 'gpio-v5.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull GPIO updates from Linus Walleij:
 "This is the big slew of GPIO changes for the v5.3 kernel cycle. This
  is mostly incremental work this time.

  Three important things:

   - The FMC subsystem is deleted through my tree. This happens through
     GPIO as its demise was discussed in relation to a patch decoupling
     its GPIO implementation from the standard way of handling GPIO. As
     it turns out, that is not the only subsystem it reimplements and
     the authors think it is better do scratch it and start over using
     the proper kernel subsystems than try to polish the rust shiny. See
     the commit (ACKed by the maintainers) for details.

   - Arnd made a small devres patch that was ACKed by Greg and goes into
     the device core.

   - SPDX header change colissions may happen, because at times I've
     seen that quite a lot changed during the -rc:s in regards to SPDX.
     (It is good stuff, tglx has me convinced, and it is worth the
     occasional pain.)

  Apart from this is is nothing controversial or problematic.

  Summary:

  Core:

   - When a gpio_chip request GPIOs from itself, it can now fully
     control the line characteristics, both machine and consumer flags.
     This makes a lot of sense, but took some time before I figured out
     that this is how it has to work.

   - Several smallish documentation fixes.

  New drivers:

   - The PCA953x driver now supports the TI TCA9539.

   - The DaVinci driver now supports the K3 AM654 SoCs.

  Driver improvements:

   - Major overhaul and hardening of the OMAP driver by Russell King.

   - Starting to move some drivers to the new API passing irq_chip along
     with the gpio_chip when adding the gpio_chip instead of adding it
     separately.

  Unrelated:

   - Delete the FMC subsystem"

* tag 'gpio-v5.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (87 commits)
  Revert "gpio: tegra: Clean-up debugfs initialisation"
  gpiolib: Use spinlock_t instead of struct spinlock
  gpio: stp-xway: allow compile-testing
  gpio: stp-xway: get rid of the #include <lantiq_soc.h> dependency
  gpio: stp-xway: improve module clock error handling
  gpio: stp-xway: simplify error handling in xway_stp_probe()
  gpiolib: Clarify use of non-sleeping functions
  gpiolib: Fix references to gpiod_[gs]et_*value_cansleep() variants
  gpiolib: Document new gpio_chip.init_valid_mask field
  Documentation: gpio: Fix reference to gpiod_get_array()
  gpio: pl061: drop duplicate printing of device name
  gpio: altera: Pass irqchip when adding gpiochip
  gpio: siox: Use devm_ managed gpiochip
  gpio: siox: Add struct device *dev helper variable
  gpio: siox: Pass irqchip when adding gpiochip
  drivers: gpio: amd-fch: make resource struct const
  devres: allow const resource arguments
  gpio: ath79: Pass irqchip when adding gpiochip
  gpio: tegra: Clean-up debugfs initialisation
  gpio: siox: Switch to IRQ_TYPE_NONE
  ...
alistair/sunxi64-5.4-dsi
Linus Torvalds 2019-07-09 09:07:00 -07:00
commit 2ec98f5678
75 changed files with 845 additions and 4220 deletions

View File

@ -5,6 +5,7 @@ Required Properties:
"ti,keystone-gpio": for Keystone 2 66AK2H/K, 66AK2L,
66AK2E SoCs
"ti,k2g-gpio", "ti,keystone-gpio": for 66AK2G
"ti,am654-gpio", "ti,keystone-gpio": for TI K3 AM654
- reg: Physical base address of the controller and the size of memory mapped
registers.
@ -145,3 +146,20 @@ gpio0: gpio@260bf00 {
ti,ngpio = <32>;
ti,davinci-gpio-unbanked = <32>;
};
Example for K3 AM654:
wkup_gpio0: wkup_gpio0@42110000 {
compatible = "ti,am654-gpio", "ti,keystone-gpio";
reg = <0x42110000 0x100>;
gpio-controller;
#gpio-cells = <2>;
interrupt-parent = <&intr_wkup_gpio>;
interrupts = <59 128>, <59 129>, <59 130>, <59 131>;
interrupt-controller;
#interrupt-cells = <2>;
ti,ngpio = <56>;
ti,davinci-gpio-unbanked = <0>;
clocks = <&k3_clks 59 0>;
clock-names = "gpio";
};

View File

@ -1,10 +0,0 @@
ARM PL061 GPIO controller
Required properties:
- compatible : "arm,pl061", "arm,primecell"
- #gpio-cells : Should be two. The first cell is the pin number and the
second cell is used to specify optional parameters:
- bit 0 specifies polarity (0 for normal, 1 for inverted)
- gpio-controller : Marks the device node as a GPIO controller.
- interrupts : Interrupt mapping for GPIO IRQ.
- gpio-ranges : Interaction with the PINCTRL subsystem.

View File

@ -0,0 +1,69 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/pl061-gpio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ARM PL061 GPIO controller
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
- Rob Herring <robh@kernel.org>
# We need a select here so we don't match all nodes with 'arm,primecell'
select:
properties:
compatible:
contains:
const: arm,pl061
required:
- compatible
properties:
$nodename:
pattern: "^gpio@[0-9a-f]+$"
compatible:
items:
- const: arm,pl061
- const: arm,primecell
reg:
maxItems: 1
interrupts:
oneOf:
- maxItems: 1
- maxItems: 8
interrupt-controller: true
"#interrupt-cells":
const: 2
clocks:
maxItems: 1
clock-names: true
"#gpio-cells":
const: 2
gpio-controller: true
gpio-ranges:
maxItems: 8
required:
- compatible
- reg
- interrupts
- interrupt-controller
- "#interrupt-cells"
- clocks
- "#gpio-cells"
- gpio-controller
additionalProperties: false
...

View File

@ -283,8 +283,6 @@ To summarize::
gpiod_set_value(desc, 1); default (active high) high
gpiod_set_value(desc, 0); active low high
gpiod_set_value(desc, 1); active low low
gpiod_set_value(desc, 0); default (active high) low
gpiod_set_value(desc, 1); default (active high) high
gpiod_set_value(desc, 0); open drain low
gpiod_set_value(desc, 1); open drain high impedance
gpiod_set_value(desc, 0); open source high impedance
@ -366,7 +364,7 @@ accessed sequentially.
The functions take three arguments:
* array_size - the number of array elements
* desc_array - an array of GPIO descriptors
* array_info - optional information obtained from gpiod_array_get()
* array_info - optional information obtained from gpiod_get_array()
* value_bitmap - a bitmap to store the GPIOs' values (get) or
a bitmap of values to assign to the GPIOs (set)

View File

@ -235,7 +235,7 @@ means that a pull up or pull-down resistor is available on the output of the
GPIO line, and this resistor is software controlled.
In discrete designs, a pull-up or pull-down resistor is simply soldered on
the circuit board. This is not something we deal or model in software. The
the circuit board. This is not something we deal with or model in software. The
most you will think about these lines is that they will very likely be
configured as open drain or open source (see the section above).
@ -292,18 +292,18 @@ We can divide GPIO irqchips in two broad categories:
- HIERARCHICAL INTERRUPT CHIPS: this means that each GPIO line has a dedicated
irq line to a parent interrupt controller one level up. There is no need
to inquire the GPIO hardware to figure out which line has figured, but it
may still be necessary to acknowledge the interrupt and set up the
configuration such as edge sensitivity.
to inquire the GPIO hardware to figure out which line has fired, but it
may still be necessary to acknowledge the interrupt and set up configuration
such as edge sensitivity.
Realtime considerations: a realtime compliant GPIO driver should not use
spinlock_t or any sleepable APIs (like PM runtime) as part of its irqchip
implementation.
- spinlock_t should be replaced with raw_spinlock_t [1].
- spinlock_t should be replaced with raw_spinlock_t.[1]
- If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
and .irq_bus_unlock() callbacks, as these are the only slowpath callbacks
on an irqchip. Create the callbacks if needed [2].
on an irqchip. Create the callbacks if needed.[2]
Cascaded GPIO irqchips
@ -361,7 +361,7 @@ Cascaded GPIO irqchips usually fall in one of three categories:
Realtime considerations: this kind of handlers will be forced threaded on -RT,
and as result the IRQ core will complain that generic_handle_irq() is called
with IRQ enabled and the same work around as for "CHAINED GPIO irqchips" can
with IRQ enabled and the same work-around as for "CHAINED GPIO irqchips" can
be applied.
- NESTED THREADED GPIO IRQCHIPS: these are off-chip GPIO expanders and any
@ -418,7 +418,7 @@ symbol:
If there is a need to exclude certain GPIO lines from the IRQ domain handled by
these helpers, we can set .irq.need_valid_mask of the gpiochip before
[devm_]gpiochip_add_data() is called. This allocates an .irq.valid_mask with as
``[devm_]gpiochip_add_data()`` is called. This allocates an .irq.valid_mask with as
many bits set as there are GPIO lines in the chip, each bit representing line
0..n-1. Drivers can exclude GPIO lines by clearing bits from this mask. The mask
must be filled in before gpiochip_irqchip_add() or gpiochip_irqchip_add_nested()

View File

@ -1,47 +0,0 @@
Functions Exported by fmc.ko
****************************
The FMC core exports the usual 4 functions that are needed for a bus to
work, and a few more:
int fmc_driver_register(struct fmc_driver *drv);
void fmc_driver_unregister(struct fmc_driver *drv);
int fmc_device_register(struct fmc_device *fmc);
void fmc_device_unregister(struct fmc_device *fmc);
int fmc_device_register_n(struct fmc_device **fmc, int n);
void fmc_device_unregister_n(struct fmc_device **fmc, int n);
uint32_t fmc_readl(struct fmc_device *fmc, int offset);
void fmc_writel(struct fmc_device *fmc, uint32_t val, int off);
void *fmc_get_drvdata(struct fmc_device *fmc);
void fmc_set_drvdata(struct fmc_device *fmc, void *data);
int fmc_reprogram(struct fmc_device *f, struct fmc_driver *d, char *gw,
int sdb_entry);
The data structure that describe a device is detailed in *note FMC
Device::, the one that describes a driver is detailed in *note FMC
Driver::. Please note that structures of type fmc_device must be
allocated by the caller, but must not be released after unregistering.
The fmc-bus itself takes care of releasing the structure when their use
count reaches zero - actually, the device model does that in lieu of us.
The functions to register and unregister n devices are meant to be used
by carriers that host more than one mezzanine. The devices must all be
registered at the same time because if the FPGA is reprogrammed, all
devices in the array are affected. Usually, the driver matching the
first device will reprogram the FPGA, so other devices must know they
are already driven by a reprogrammed FPGA.
If a carrier hosts slots that are driven by different FPGA devices, it
should register as a group only mezzanines that are driven by the same
FPGA, for the reason outlined above.
Finally, the fmc_reprogram function calls the reprogram method (see
*note The API Offered by Carriers:: and also scans the memory area for
an SDB tree. You can pass -1 as sdb_entry to disable such scan.
Otherwise, the function fails if no tree is found at the specified
entry point. The function is meant to factorize common code, and by
the time you read this it is already used by the spec-sw and fine-delay
modules.

View File

@ -1,88 +0,0 @@
FMC (FPGA Mezzanine Card) is the standard we use for our I/O devices,
in the context of White Rabbit and related hardware.
In our I/O environments we need to write drivers for each mezzanine
card, and such drivers must work regardless of the carrier being used.
To achieve this, we abstract the FMC interface.
We have a carrier for PCI-E called SPEC and one for VME called SVEC,
but more are planned. Also, we support stand-alone devices (usually
plugged on a SPEC card), controlled through Etherbone, developed by GSI.
Code and documentation for the FMC bus was born as part of the spec-sw
project, but now it lives in its own project. Other projects, i.e.
software support for the various carriers, should include this as a
submodule.
The most up to date version of code and documentation is always
available from the repository you can clone from:
git://ohwr.org/fmc-projects/fmc-bus.git (read-only)
git@ohwr.org:fmc-projects/fmc-bus.git (read-write for developers)
Selected versions of the documentation, as well as complete tar
archives for selected revisions are placed to the Files section of the
project: `http://www.ohwr.org/projects/fmc-bus/files'
What is FMC
***********
FMC, as said, stands for "FPGA Mezzanine Card". It is a standard
developed by the VME consortium called VITA (VMEbus International Trade
Association and ratified by ANSI, the American National Standard
Institute. The official documentation is called "ANSI-VITA 57.1".
The FMC card is an almost square PCB, around 70x75 millimeters, that is
called mezzanine in this document. It usually lives plugged into
another PCB for power supply and control; such bigger circuit board is
called carrier from now on, and a single carrier may host more than one
mezzanine.
In the typical application the mezzanine is mostly analog while the
carrier is mostly digital, and hosts an FPGA that must be configured to
match the specific mezzanine and the desired application. Thus, you may
need to load different FPGA images to drive different instances of the
same mezzanine.
FMC, as such, is not a bus in the usual meaning of the term, because
most carriers have only one connector, and carriers with several
connectors have completely separate electrical connections to them.
This package, however, implements a bus as a software abstraction.
What is SDB
***********
SDB (Self Describing Bus) is a set of data structures that we use for
enumerating the internal structure of an FPGA image. We also use it as
a filesystem inside the FMC EEPROM.
SDB is not mandatory for use of this FMC kernel bus, but if you have SDB
this package can make good use of it. SDB itself is developed in the
fpga-config-space OHWR project. The link to the repository is
`git://ohwr.org/hdl-core-lib/fpga-config-space.git' and what is used in
this project lives in the sdbfs subdirectory in there.
SDB support for FMC is described in *note FMC Identification:: and
*note SDB Support::
SDB Support
***********
The fmc.ko bus driver exports a few functions to help drivers taking
advantage of the SDB information that may be present in your own FPGA
memory image.
The module exports the following functions, in the special header
<linux/fmc-sdb.h>. The linux/ prefix in the name is there because we
plan to submit it upstream in the future, and don't want to force
changes on our drivers if that happens.
int fmc_scan_sdb_tree(struct fmc_device *fmc, unsigned long address);
void fmc_show_sdb_tree(struct fmc_device *fmc);
signed long fmc_find_sdb_device(struct sdb_array *tree, uint64_t vendor,
uint32_t device, unsigned long *sz);
int fmc_free_sdb_tree(struct fmc_device *fmc);

View File

@ -1,311 +0,0 @@
FMC Device
**********
Within the Linux bus framework, the FMC device is created and
registered by the carrier driver. For example, the PCI driver for the
SPEC card fills a data structure for each SPEC that it drives, and
registers an associated FMC device for each card. The SVEC driver can
do exactly the same for the VME carrier (actually, it should do it
twice, because the SVEC carries two FMC mezzanines). Similarly, an
Etherbone driver will be able to register its own FMC devices, offering
communication primitives through frame exchange.
The contents of the EEPROM within the FMC are used for identification
purposes, i.e. for matching the device with its own driver. For this
reason the device structure includes a complete copy of the EEPROM
(actually, the carrier driver may choose whether or not to return it -
for example we most likely won't have the whole EEPROM available for
Etherbone devices.
The following listing shows the current structure defining a device.
Please note that all the machinery is in place but some details may
still change in the future. For this reason, there is a version field
at the beginning of the structure. As usual, the minor number will
change for compatible changes (like a new flag) and the major number
will increase when an incompatible change happens (for example, a
change in layout of some fmc data structures). Device writers should
just set it to the value FMC_VERSION, and be ready to get back -EINVAL
at registration time.
struct fmc_device {
unsigned long version;
unsigned long flags;
struct module *owner; /* char device must pin it */
struct fmc_fru_id id; /* for EEPROM-based match */
struct fmc_operations *op; /* carrier-provided */
int irq; /* according to host bus. 0 == none */
int eeprom_len; /* Usually 8kB, may be less */
int eeprom_addr; /* 0x50, 0x52 etc */
uint8_t *eeprom; /* Full contents or leading part */
char *carrier_name; /* "SPEC" or similar, for special use */
void *carrier_data; /* "struct spec *" or equivalent */
__iomem void *fpga_base; /* May be NULL (Etherbone) */
__iomem void *slot_base; /* Set by the driver */
struct fmc_device **devarray; /* Allocated by the bus */
int slot_id; /* Index in the slot array */
int nr_slots; /* Number of slots in this carrier */
unsigned long memlen; /* Used for the char device */
struct device dev; /* For Linux use */
struct device *hwdev; /* The underlying hardware device */
unsigned long sdbfs_entry;
struct sdb_array *sdb;
uint32_t device_id; /* Filled by the device */
char *mezzanine_name; /* Defaults to ``fmc'' */
void *mezzanine_data;
};
The meaning of most fields is summarized in the code comment above.
The following fields must be filled by the carrier driver before
registration:
* version: must be set to FMC_VERSION.
* owner: set to MODULE_OWNER.
* op: the operations to act on the device.
* irq: number for the mezzanine; may be zero.
* eeprom_len: length of the following array.
* eeprom_addr: 0x50 for first mezzanine and so on.
* eeprom: the full content of the I2C EEPROM.
* carrier_name.
* carrier_data: a unique pointer for the carrier.
* fpga_base: the I/O memory address (may be NULL).
* slot_id: the index of this slot (starting from zero).
* memlen: if fpga_base is valid, the length of I/O memory.
* hwdev: to be used in some dev_err() calls.
* device_id: a slot-specific unique integer number.
Please note that the carrier should read its own EEPROM memory before
registering the device, as well as fill all other fields listed above.
The following fields should not be assigned, because they are filled
later by either the bus or the device driver:
* flags.
* fru_id: filled by the bus, parsing the eeprom.
* slot_base: filled and used by the driver, if useful to it.
* devarray: an array og all mezzanines driven by a singe FPGA.
* nr_slots: set by the core at registration time.
* dev: used by Linux.
* sdb: FPGA contents, scanned according to driver's directions.
* sdbfs_entry: SDB entry point in EEPROM: autodetected.
* mezzanine_data: available for the driver.
* mezzanine_name: filled by fmc-bus during identification.
Note: mezzanine_data may be redundant, because Linux offers the drvdata
approach, so the field may be removed in later versions of this bus
implementation.
As I write this, she SPEC carrier is already completely functional in
the fmc-bus environment, and is a good reference to look at.
The API Offered by Carriers
===========================
The carrier provides a number of methods by means of the
`fmc_operations' structure, which currently is defined like this
(again, it is a moving target, please refer to the header rather than
this document):
struct fmc_operations {
uint32_t (*readl)(struct fmc_device *fmc, int offset);
void (*writel)(struct fmc_device *fmc, uint32_t value, int offset);
int (*reprogram)(struct fmc_device *f, struct fmc_driver *d, char *gw);
int (*validate)(struct fmc_device *fmc, struct fmc_driver *drv);
int (*irq_request)(struct fmc_device *fmc, irq_handler_t h,
char *name, int flags);
void (*irq_ack)(struct fmc_device *fmc);
int (*irq_free)(struct fmc_device *fmc);
int (*gpio_config)(struct fmc_device *fmc, struct fmc_gpio *gpio,
int ngpio);
int (*read_ee)(struct fmc_device *fmc, int pos, void *d, int l);
int (*write_ee)(struct fmc_device *fmc, int pos, const void *d, int l);
};
The individual methods perform the following tasks:
`readl'
`writel'
These functions access FPGA registers by whatever means the
carrier offers. They are not expected to fail, and most of the time
they will just make a memory access to the host bus. If the
carrier provides a fpga_base pointer, the driver may use direct
access through that pointer. For this reason the header offers the
inline functions fmc_readl and fmc_writel that access fpga_base if
the respective method is NULL. A driver that wants to be portable
and efficient should use fmc_readl and fmc_writel. For Etherbone,
or other non-local carriers, error-management is still to be
defined.
`validate'
Module parameters are used to manage different applications for
two or more boards of the same kind. Validation is based on the
busid module parameter, if provided, and returns the matching
index in the associated array. See *note Module Parameters:: in in
doubt. If no match is found, `-ENOENT' is returned; if the user
didn't pass `busid=', all devices will pass validation. The value
returned by the validate method can be used as index into other
parameters (for example, some drivers use the `lm32=' parameter in
this way). Such "generic parameters" are documented in *note
Module Parameters::, below. The validate method is used by
`fmc-trivial.ko', described in *note fmc-trivial::.
`reprogram'
The carrier enumerates FMC devices by loading a standard (or
golden) FPGA binary that allows EEPROM access. Each driver, then,
will need to reprogram the FPGA by calling this function. If the
name argument is NULL, the carrier should reprogram the golden
binary. If the gateware name has been overridden through module
parameters (in a carrier-specific way) the file loaded will match
the parameters. Per-device gateware names can be specified using
the `gateware=' parameter, see *note Module Parameters::. Note:
Clients should call rhe new helper, fmc_reprogram, which both
calls this method and parse the SDB tree of the FPGA.
`irq_request'
`irq_ack'
`irq_free'
Interrupt management is carrier-specific, so it is abstracted as
operations. The interrupt number is listed in the device
structure, and for the mezzanine driver the number is only
informative. The handler will receive the fmc pointer as dev_id;
the flags argument is passed to the Linux request_irq function,
but fmc-specific flags may be added in the future. You'll most
likely want to pass the `IRQF_SHARED' flag.
`gpio_config'
The method allows to configure a GPIO pin in the carrier, and read
its current value if it is configured as input. See *note The GPIO
Abstraction:: for details.
`read_ee'
`write_ee'
Read or write the EEPROM. The functions are expected to be only
called before reprogramming and the carrier should refuse them
with `ENODEV' after reprogramming. The offset is expected to be
within 8kB (the current size), but addresses up to 1MB are
reserved to fit bigger I2C devices in the future. Carriers may
offer access to other internal flash memories using these same
methods: for example the SPEC driver may define that its carrier
I2C memory is seen at offset 1M and the internal SPI flash is seen
at offset 16M. This multiplexing of several flash memories in the
same address space is carrier-specific and should only be used
by a driver that has verified the `carrier_name' field.
The GPIO Abstraction
====================
Support for GPIO pins in the fmc-bus environment is not very
straightforward and deserves special discussion.
While the general idea of a carrier-independent driver seems to fly,
configuration of specific signals within the carrier needs at least
some knowledge of the carrier itself. For this reason, the specific
driver can request to configure carrier-specific GPIO pins, numbered
from 0 to at most 4095. Configuration is performed by passing a
pointer to an array of struct fmc_gpio items, as well as the length of
the array. This is the data structure:
struct fmc_gpio {
char *carrier_name;
int gpio;
int _gpio; /* internal use by the carrier */
int mode; /* GPIOF_DIR_OUT etc, from <linux/gpio.h> */
int irqmode; /* IRQF_TRIGGER_LOW and so on */
};
By specifying a carrier_name for each pin, the driver may access
different pins in different carriers. The gpio_config method is
expected to return the number of pins successfully configured, ignoring
requests for other carriers. However, if no pin is configured (because
no structure at all refers to the current carrier_name), the operation
returns an error so the caller will know that it is running under a
yet-unsupported carrier.
So, for example, a driver that has been developed and tested on both
the SPEC and the SVEC may request configuration of two different GPIO
pins, and expect one such configuration to succeed - if none succeeds
it most likely means that the current carrier is a still-unknown one.
If, however, your GPIO pin has a specific known role, you can pass a
special number in the gpio field, using one of the following macros:
#define FMC_GPIO_RAW(x) (x) /* 4096 of them */
#define FMC_GPIO_IRQ(x) ((x) + 0x1000) /* 256 of them */
#define FMC_GPIO_LED(x) ((x) + 0x1100) /* 256 of them */
#define FMC_GPIO_KEY(x) ((x) + 0x1200) /* 256 of them */
#define FMC_GPIO_TP(x) ((x) + 0x1300) /* 256 of them */
#define FMC_GPIO_USER(x) ((x) + 0x1400) /* 256 of them */
Use of virtual GPIO numbers (anything but FMC_GPIO_RAW) is allowed
provided the carrier_name field in the data structure is left
unspecified (NULL). Each carrier is responsible for providing a mapping
between virtual and physical GPIO numbers. The carrier may then use the
_gpio field to cache the result of this mapping.
All carriers must map their I/O lines to the sets above starting from
zero. The SPEC, for example, maps interrupt pins 0 and 1, and test
points 0 through 3 (even if the test points on the PCB are called
5,6,7,8).
If, for example, a driver requires a free LED and a test point (for a
scope probe to be plugged at some point during development) it may ask
for FMC_GPIO_LED(0) and FMC_GPIO_TP(0). Each carrier will provide
suitable GPIO pins. Clearly, the person running the drivers will know
the order used by the specific carrier driver in assigning leds and
testpoints, so to make a carrier-dependent use of the diagnostic tools.
In theory, some form of autodetection should be possible: a driver like
the wr-nic (which uses IRQ(1) on the SPEC card) should configure
IRQ(0), make a test with software-generated interrupts and configure
IRQ(1) if the test fails. This probing step should be used because even
if the wr-nic gateware is known to use IRQ1 on the SPEC, the driver
should be carrier-independent and thus use IRQ(0) as a first bet -
actually, the knowledge that IRQ0 may fail is carrier-dependent
information, but using it doesn't make the driver unsuitable for other
carriers.
The return value of gpio_config is defined as follows:
* If no pin in the array can be used by the carrier, `-ENODEV'.
* If at least one virtual GPIO number cannot be mapped, `-ENOENT'.
* On success, 0 or positive. The value returned is the number of
high input bits (if no input is configured, the value for success
is 0).
While I admit the procedure is not completely straightforward, it
allows configuration, input and output with a single carrier operation.
Given the typical use case of FMC devices, GPIO operations are not
expected to ever by in hot paths, and GPIO access so fare has only been
used to configure the interrupt pin, mode and polarity. Especially
reading inputs is not expected to be common. If your device has GPIO
capabilities in the hot path, you should consider using the kernel's
GPIO mechanisms.

View File

@ -1,64 +0,0 @@
fmc-chardev
===========
This is a simple generic driver, that allows user access by means of a
character device (actually, one for each mezzanine it takes hold of).
The char device is created as a misc device. Its name in /dev (as
created by udev) is the same name as the underlying FMC device. Thus,
the name can be a silly fmc-0000 look-alike if the device has no
identifiers nor bus_id, a more specific fmc-0400 if the device has a
bus-specific address but no associated name, or something like
fdelay-0400 if the FMC core can rely on both a mezzanine name and a bus
address.
Currently the driver only supports read and write: you can lseek to the
desired address and read or write a register.
The driver assumes all registers are 32-bit in size, and only accepts a
single read or write per system call. However, as a result of Unix read
and write semantics, users can simply fread or fwrite bigger areas in
order to dump or store bigger memory areas.
There is currently no support for mmap, user-space interrupt management
and DMA buffers. They may be added in later versions, if the need
arises.
The example below shows raw access to a SPEC card programmed with its
golden FPGA file, that features an SDB structure at offset 256 - i.e.
64 words. The mezzanine's EEPROM in this case is not programmed, so the
default name is fmc-<bus><devfn>, and there are two cards in the system:
spusa.root# insmod fmc-chardev.ko
[ 1073.339332] spec 0000:02:00.0: Driver has no ID: matches all
[ 1073.345051] spec 0000:02:00.0: Created misc device "fmc-0200"
[ 1073.350821] spec 0000:04:00.0: Driver has no ID: matches all
[ 1073.356525] spec 0000:04:00.0: Created misc device "fmc-0400"
spusa.root# ls -l /dev/fmc*
crw------- 1 root root 10, 58 Nov 20 19:23 /dev/fmc-0200
crw------- 1 root root 10, 57 Nov 20 19:23 /dev/fmc-0400
spusa.root# dd bs=4 skip=64 count=1 if=/dev/fmc-0200 2> /dev/null | od -t x1z
0000000 2d 42 44 53 >-BDS<
0000004
The simple program tools/fmc-mem in this package can access an FMC char
device and read or write a word or a whole area. Actually, the program
is not specific to FMC at all, it just uses lseek, read and write.
Its first argument is the device name, the second the offset, the third
(if any) the value to write and the optional last argument that must
begin with "+" is the number of bytes to read or write. In case of
repeated reading data is written to stdout; repeated writes read from
stdin and the value argument is ignored.
The following examples show reading the SDB magic number and the first
SDB record from a SPEC device programmed with its golden image:
spusa.root# ./fmc-mem /dev/fmc-0200 100
5344422d
spusa.root# ./fmc-mem /dev/fmc-0200 100 +40 | od -Ax -t x1z
000000 2d 42 44 53 00 01 02 00 00 00 00 00 00 00 00 00 >-BDS............<
000010 00 00 00 00 ff 01 00 00 00 00 00 00 51 06 00 00 >............Q...<
000020 c9 42 a5 e6 02 00 00 00 11 05 12 20 2d 34 42 57 >.B......... -4BW<
000030 73 6f 72 43 72 61 62 73 49 53 47 2d 00 20 20 20 >sorCrabsISG-. <
000040

View File

@ -1,36 +0,0 @@
fmc-fakedev
===========
This package includes a software-only device, called fmc-fakedev, which
is able to register up to 4 mezzanines (by default it registers one).
Unlike the SPEC driver, which creates an FMC device for each PCI cards
it manages, this module creates a single instance of its set of
mezzanines.
It is meant as the simplest possible example of how a driver should be
written, and it includes a fake EEPROM image (built using the tools
described in *note FMC Identification::),, which by default is
replicated for each fake mezzanine.
You can also use this device to verify the match algorithms, by asking
it to test your own EEPROM image. You can provide the image by means of
the eeprom= module parameter: the new EEPROM image is loaded, as usual,
by means of the firmware loader. This example shows the defaults and a
custom EEPROM image:
spusa.root# insmod fmc-fakedev.ko
[ 99.971247] fake-fmc-carrier: mezzanine 0
[ 99.975393] Manufacturer: fake-vendor
[ 99.979624] Product name: fake-design-for-testing
spusa.root# rmmod fmc-fakedev
spusa.root# insmod fmc-fakedev.ko eeprom=fdelay-eeprom.bin
[ 121.447464] fake-fmc-carrier: Mezzanine 0: eeprom "fdelay-eeprom.bin"
[ 121.462725] fake-fmc-carrier: mezzanine 0
[ 121.466858] Manufacturer: CERN
[ 121.470477] Product name: FmcDelay1ns4cha
spusa.root# rmmod fmc-fakedev
After loading the device, you can use the write_ee method do modify its
own internal fake EEPROM: whenever the image is overwritten starting at
offset 0, the module will unregister and register again the FMC device.
This is shown in fmc-write-eeprom.txt

View File

@ -1,17 +0,0 @@
fmc-trivial
===========
The simple module fmc-trivial is just a simple client that registers an
interrupt handler. I used it to verify the basic mechanism of the FMC
bus and how interrupts worked.
The module implements the generic FMC parameters, so it can program a
different gateware file in each card. The whole list of parameters it
accepts are:
`busid='
`gateware='
Generic parameters. See mezzanine.txt
This driver is worth reading, in my opinion.

View File

@ -1,98 +0,0 @@
fmc-write-eeprom
================
This module is designed to load a binary file from /lib/firmware and to
write it to the internal EEPROM of the mezzanine card. This driver uses
the `busid' generic parameter.
Overwriting the EEPROM is not something you should do daily, and it is
expected to only happen during manufacturing. For this reason, the
module makes it unlikely for the random user to change a working EEPROM.
However, since the EEPROM may include application-specific information
other than the identification, later versions of this packages added
write-support through sysfs. See *note Accessing the EEPROM::.
To avoid damaging the EEPROM content, the module takes the following
measures:
* It accepts a `file=' argument (within /lib/firmware) and if no
such argument is received, it doesn't write anything to EEPROM
(i.e. there is no default file name).
* If the file name ends with `.bin' it is written verbatim starting
at offset 0.
* If the file name ends with `.tlv' it is interpreted as
type-length-value (i.e., it allows writev(2)-like operation).
* If the file name doesn't match any of the patterns above, it is
ignored and no write is performed.
* Only cards listed with `busid=' are written to. If no busid is
specified, no programming is done (and the probe function of the
driver will fail).
Each TLV tuple is formatted in this way: the header is 5 bytes,
followed by data. The first byte is `w' for write, the next two bytes
represent the address, in little-endian byte order, and the next two
represent the data length, in little-endian order. The length does not
include the header (it is the actual number of bytes to be written).
This is a real example: that writes 5 bytes at position 0x110:
spusa.root# od -t x1 -Ax /lib/firmware/try.tlv
000000 77 10 01 05 00 30 31 32 33 34
00000a
spusa.root# insmod /tmp/fmc-write-eeprom.ko busid=0x0200 file=try.tlv
[19983.391498] spec 0000:03:00.0: write 5 bytes at 0x0110
[19983.414615] spec 0000:03:00.0: write_eeprom: success
Please note that you'll most likely want to use SDBFS to build your
EEPROM image, at least if your mezzanines are being used in the White
Rabbit environment. For this reason the TLV format is not expected to
be used much and is not expected to be developed further.
If you want to try reflashing fake EEPROM devices, you can use the
fmc-fakedev.ko module (see *note fmc-fakedev::). Whenever you change
the image starting at offset 0, it will deregister and register again
after two seconds. Please note, however, that if fmc-write-eeprom is
still loaded, the system will associate it to the new device, which
will be reprogrammed and thus will be unloaded after two seconds. The
following example removes the module after it reflashed fakedev the
first time.
spusa.root# insmod fmc-fakedev.ko
[ 72.984733] fake-fmc: Manufacturer: fake-vendor
[ 72.989434] fake-fmc: Product name: fake-design-for-testing
spusa.root# insmod fmc-write-eeprom.ko busid=0 file=fdelay-eeprom.bin; \
rmmod fmc-write-eeprom
[ 130.874098] fake-fmc: Matching a generic driver (no ID)
[ 130.887845] fake-fmc: programming 6155 bytes
[ 130.894567] fake-fmc: write_eeprom: success
[ 132.895794] fake-fmc: Manufacturer: CERN
[ 132.899872] fake-fmc: Product name: FmcDelay1ns4cha
Accessing the EEPROM
=====================
The bus creates a sysfs binary file called eeprom for each mezzanine it
knows about:
spusa.root# cd /sys/bus/fmc/devices; ls -l */eeprom
-r--r--r-- 1 root root 8192 Feb 21 12:30 FmcAdc100m14b4cha-0800/eeprom
-r--r--r-- 1 root root 8192 Feb 21 12:30 FmcDelay1ns4cha-0200/eeprom
-r--r--r-- 1 root root 8192 Feb 21 12:30 FmcDio5cha-0400/eeprom
Everybody can read the files and the superuser can also modify it, but
the operation may on the carrier driver, if the carrier is unable to
access the I2C bus. For example, the spec driver can access the bus
only with its golden gateware: after a mezzanine driver reprogrammed
the FPGA with a custom circuit, the carrier is unable to access the
EEPROM and returns ENOTSUPP.
An alternative way to write the EEPROM is the mezzanine driver
fmc-write-eeprom (See *note fmc-write-eeprom::), but the procedure is
more complex.

View File

@ -1,168 +0,0 @@
FMC Identification
******************
The FMC standard requires every compliant mezzanine to carry
identification information in an I2C EEPROM. The information must be
laid out according to the "IPMI Platform Management FRU Information",
where IPMI is a lie I'd better not expand, and FRU means "Field
Replaceable Unit".
The FRU information is an intricate unreadable binary blob that must
live at offset 0 of the EEPROM, and typically extends for a few hundred
bytes. The standard allows the application to use all the remaining
storage area of the EEPROM as it wants.
This chapter explains how to create your own EEPROM image and how to
write it in your mezzanine, as well as how devices and drivers are
paired at run time. EEPROM programming uses tools that are part of this
package and SDB (part of the fpga-config-space package).
The first sections are only interesting for manufacturers who need to
write the EEPROM. If you are just a software developer writing an FMC
device or driver, you may jump straight to *note SDB Support::.
Building the FRU Structure
==========================
If you want to know the internals of the FRU structure and despair, you
can retrieve the document from
`http://download.intel.com/design/servers/ipmi/FRU1011.pdf' . The
standard is awful and difficult without reason, so we only support the
minimum mandatory subset - we create a simple structure and parse it
back at run time, but we are not able to either generate or parse more
arcane features like non-english languages and 6-bit text. If you need
more items of the FRU standard for your boards, please submit patches.
This package includes the Python script that Matthieu Cattin wrote to
generate the FRU binary blob, based on an helper libipmi by Manohar
Vanga and Matthieu himself. I changed the test script to receive
parameters from the command line or from the environment (the command
line takes precedence)
To make a long story short, in order to build a standard-compliant
binary file to be burned in your EEPROM, you need the following items:
Environment Opt Official Name Default
---------------------------------------------------------------------
FRU_VENDOR -v "Board Manufacturer" fmc-example
FRU_NAME -n "Board Product Name" mezzanine
FRU_SERIAL -s `Board Serial Number" 0001
FRU_PART -p "Board Part Number" sample-part
FRU_OUTPUT -o not applicable /dev/stdout
The "Official Name" above is what you find in the FRU official
documentation, chapter 11, page 7 ("Board Info Area Format"). The
output option is used to save the generated binary to a specific file
name instead of stdout.
You can pass the items to the FRU generator either in the environment
or on the command line. This package has currently no support for
specifying power consumption or such stuff, but I plan to add it as
soon as I find some time for that.
FIXME: consumption etc for FRU are here or in PTS?
The following example creates a binary image for a specific board:
./tools/fru-generator -v CERN -n FmcAdc100m14b4cha \
-s HCCFFIA___-CR000003 -p EDA-02063-V5-0 > eeprom.bin
The following example shows a script that builds several binary EEPROM
images for a series of boards, changing the serial number for each of
them. The script uses a mix of environment variables and command line
options, and uses the same string patterns shown above.
#!/bin/sh
export FRU_VENDOR="CERN"
export FRU_NAME="FmcAdc100m14b4cha"
export FRU_PART="EDA-02063-V5-0"
serial="HCCFFIA___-CR"
for number in $(seq 1 50); do
# build number-string "ns"
ns="$(printf %06d $number)"
./fru-generator -s "${serial}${ns}" > eeprom-${ns}.bin
done
Using SDB-FS in the EEPROM
==========================
If you want to use SDB as a filesystem in the EEPROM device within the
mezzanine, you should create one such filesystem using gensdbfs, from
the fpga-config-space package on OHWR.
By using an SBD filesystem you can cluster several files in a single
EEPROM, so both the host system and a soft-core running in the FPGA (if
any) can access extra production-time information.
We chose to use SDB as a storage filesystem because the format is very
simple, and both the host system and the soft-core will likely already
include support code for such format. The SDB library offered by the
fpga-config-space is less than 1kB under LM32, so it proves quite up to
the task.
The SDB entry point (which acts as a directory listing) cannot live at
offset zero in the flash device, because the FRU information must live
there. To avoid wasting precious storage space while still allowing
for more-than-minimal FRU structures, the fmc.ko will look for the SDB
record at address 256, 512 and 1024.
In order to generate the complete EEPROM image you'll need a
configuration file for gensdbfs: you tell the program where to place
the sdb entry point, and you must force the FRU data file to be placed
at the beginning of the storage device. If needed, you can also place
other files at a special offset (we sometimes do it for backward
compatibility with drivers we wrote before implementing SDB for flash
memory).
The directory tools/sdbfs of this package includes a well-commented
example that you may want to use as a starting point (the comments are
in the file called -SDB-CONFIG-). Reading documentation for gensdbfs
is a suggested first step anyways.
This package (generic FMC bus support) only accesses two files in the
EEPROM: the FRU information, at offset zero, with a suggested filename
of IPMI-FRU and the short name for the mezzanine, in a file called
name. The IPMI-FRU name is not mandatory, but a strongly suggested
choice; the name filename is mandatory, because this is the preferred
short name used by the FMC core. For example, a name of "fdelay" may
supplement a Product Name like "FmcDelay1ns4cha" - exactly as
demonstrated in `tools/sdbfs'.
Note: SDB access to flash memory is not yet supported, so the short
name currently in use is just the "Product Name" FRU string.
The example in tools/sdbfs includes an extra file, that is needed by
the fine-delay driver, and must live at a known address of 0x1800. By
running gensdbfs on that directory you can output your binary EEPROM
image (here below spusa$ is the shell prompt):
spusa$ ../fru-generator -v CERN -n FmcDelay1ns4cha -s proto-0 \
-p EDA-02267-V3 > IPMI-FRU
spusa$ ls -l
total 16
-rw-rw-r-- 1 rubini staff 975 Nov 19 18:08 --SDB-CONFIG--
-rw-rw-r-- 1 rubini staff 216 Nov 19 18:13 IPMI-FRU
-rw-rw-r-- 1 rubini staff 11 Nov 19 18:04 fd-calib
-rw-rw-r-- 1 rubini staff 7 Nov 19 18:04 name
spusa$ sudo gensdbfs . /lib/firmware/fdelay-eeprom.bin
spusa$ sdb-read -l -e 0x100 /lib/firmware/fdelay-eeprom.bin
/home/rubini/wip/sdbfs/userspace/sdb-read: listing format is to be defined
46696c6544617461:2e202020 00000100-000018ff .
46696c6544617461:6e616d65 00000200-00000206 name
46696c6544617461:66642d63 00001800-000018ff fd-calib
46696c6544617461:49504d49 00000000-000000d7 IPMI-FRU
spusa$ ../fru-dump /lib/firmware/fdelay-eeprom.bin
/lib/firmware/fdelay-eeprom.bin: manufacturer: CERN
/lib/firmware/fdelay-eeprom.bin: product-name: FmcDelay1ns4cha
/lib/firmware/fdelay-eeprom.bin: serial-number: proto-0
/lib/firmware/fdelay-eeprom.bin: part-number: EDA-02267-V3
As expected, the output file is both a proper sdbfs object and an IPMI
FRU information blob. The fd-calib file lives at offset 0x1800 and is
over-allocated to 256 bytes, according to the configuration file for
gensdbfs.

View File

@ -1,123 +0,0 @@
FMC Driver
**********
An FMC driver is concerned with the specific mezzanine and associated
gateware. As such, it is expected to be independent of the carrier
being used: it will perform I/O accesses only by means of
carrier-provided functions.
The matching between device and driver is based on the content of the
EEPROM (as mandated by the FMC standard) or by the actual cores
configured in the FPGA; the latter technique is used when the FPGA is
already programmed when the device is registered to the bus core.
In some special cases it is possible for a driver to directly access
FPGA registers, by means of the `fpga_base' field of the device
structure. This may be needed for high-bandwidth peripherals like fast
ADC cards. If the device module registered a remote device (for example
by means of Etherbone), the `fpga_base' pointer will be NULL.
Therefore, drivers must be ready to deal with NULL base pointers, and
fail gracefully. Most driver, however, are not expected to access the
pointer directly but run fmc_readl and fmc_writel instead, which will
work in any case.
In even more special cases, the driver may access carrier-specific
functionality: the `carrier_name' string allows the driver to check
which is the current carrier and make use of the `carrier_data'
pointer. We chose to use carrier names rather than numeric identifiers
for greater flexibility, but also to avoid a central registry within
the `fmc.h' file - we hope other users will exploit our framework with
their own carriers. An example use of carrier names is in GPIO setup
(see *note The GPIO Abstraction::), although the name match is not
expected to be performed by the driver. If you depend on specific
carriers, please check the carrier name and fail gracefully if your
driver finds it is running in a yet-unknown-to-it environment.
ID Table
========
Like most other Linux drivers, and FMC driver must list all the devices
which it is able to drive. This is usually done by means of a device
table, but in FMC we can match hardware based either on the contents of
their EEPROM or on the actual FPGA cores that can be enumerated.
Therefore, we have two tables of identifiers.
Matching of FRU information depends on two names, the manufacturer (or
vendor) and the device (see *note FMC Identification::); for
flexibility during production (i.e. before writing to the EEPROM) the
bus supports a catch-all driver that specifies NULL strings. For this
reason, the table is specified as pointer-and-length, not a a
null-terminated array - the entry with NULL names can be a valid entry.
Matching on FPGA cores depends on two numeric fields: the 64-bit vendor
number and the 32-bit device number. Support for matching based on
class is not yet implemented. Each device is expected to be uniquely
identified by an array of cores (it matches if all of the cores are
instantiated), and for consistency the list is passed as
pointer-and-length. Several similar devices can be driven by the same
driver, and thus the driver specifies and array of such arrays.
The complete set of involved data structures is thus the following:
struct fmc_fru_id { char *manufacturer; char *product_name; };
struct fmc_sdb_one_id { uint64_t vendor; uint32_t device; };
struct fmc_sdb_id { struct fmc_sdb_one_id *cores; int cores_nr; };
struct fmc_device_id {
struct fmc_fru_id *fru_id; int fru_id_nr;
struct fmc_sdb_id *sdb_id; int sdb_id_nr;
};
A better reference, with full explanation, is the <linux/fmc.h> header.
Module Parameters
=================
Most of the FMC drivers need the same set of kernel parameters. This
package includes support to implement common parameters by means of
fields in the `fmc_driver' structure and simple macro definitions.
The parameters are carrier-specific, in that they rely on the busid
concept, that varies among carriers. For the SPEC, the identifier is a
PCI bus and devfn number, 16 bits wide in total; drivers for other
carriers will most likely offer something similar but not identical,
and some code duplication is unavoidable.
This is the list of parameters that are common to several modules to
see how they are actually used, please look at spec-trivial.c.
`busid='
This is an array of integers, listing carrier-specific
identification numbers. For PIC, for example, `0x0400' represents
bus 4, slot 0. If any such ID is specified, the driver will only
accept to drive cards that appear in the list (even if the FMC ID
matches). This is accomplished by the validate carrier method.
`gateware='
The argument is an array of strings. If no busid= is specified,
the first string of gateware= is used for all cards; otherwise the
identifiers and gateware names are paired one by one, in the order
specified.
`show_sdb='
For modules supporting it, this parameter asks to show the SDB
internal structure by means of kernel messages. It is disabled by
default because those lines tend to hide more important messages,
if you look at the system console while loading the drivers.
Note: the parameter is being obsoleted, because fmc.ko itself now
supports dump_sdb= that applies to every client driver.
For example, if you are using the trivial driver to load two different
gateware files to two different cards, you can use the following
parameters to load different binaries to the cards, after looking up
the PCI identifiers. This has been tested with a SPEC carrier.
insmod fmc-trivial.ko \
busid=0x0200,0x0400 \
gateware=fmc/fine-delay.bin,fmc/simple-dio.bin
Please note that not all sub-modules support all of those parameters.
You can use modinfo to check what is supported by each module.

View File

@ -1,56 +0,0 @@
Module Parameters in fmc.ko
***************************
The core driver receives two module parameters, meant to help debugging
client modules. Both parameters can be modified by writing to
/sys/module/fmc/parameters/, because they are used when client drivers
are devices are registered, not when fmc.ko is loaded.
`dump_eeprom='
If not zero, the parameter asks the bus controller to dump the
EEPROM of any device that is registered, using printk.
`dump_sdb='
If not zero, the parameter prints the SDB tree of every FPGA it is
loaded by fmc_reprogram(). If greater than one, it asks to dump
the binary content of SDB records. This currently only dumps the
top-level SDB array, though.
EEPROM dumping avoids repeating lines, since most of the contents is
usually empty and all bits are one or zero. This is an example of the
output:
[ 6625.850480] spec 0000:02:00.0: FPGA programming successful
[ 6626.139949] spec 0000:02:00.0: Manufacturer: CERN
[ 6626.144666] spec 0000:02:00.0: Product name: FmcDelay1ns4cha
[ 6626.150370] FMC: mezzanine 0: 0000:02:00.0 on SPEC
[ 6626.155179] FMC: dumping eeprom 0x2000 (8192) bytes
[ 6626.160087] 0000: 01 00 00 01 00 0b 00 f3 01 0a 00 a5 85 87 c4 43
[ 6626.167069] 0010: 45 52 4e cf 46 6d 63 44 65 6c 61 79 31 6e 73 34
[ 6626.174019] 0020: 63 68 61 c7 70 72 6f 74 6f 2d 30 cc 45 44 41 2d
[ 6626.180975] 0030: 30 32 32 36 37 2d 56 33 da 32 30 31 32 2d 31 31
[...]
[ 6626.371366] 0200: 66 64 65 6c 61 79 0a 00 00 00 00 00 00 00 00 00
[ 6626.378359] 0210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 6626.385361] [...]
[ 6626.387308] 1800: 70 6c 61 63 65 68 6f 6c 64 65 72 ff ff ff ff ff
[ 6626.394259] 1810: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 6626.401250] [...]
The dump of SDB looks like the following; the example shows the simple
golden gateware for the SPEC card, removing the leading timestamps to
fit the page:
spec 0000:02:00.0: SDB: 00000651:e6a542c9 WB4-Crossbar-GSI
spec 0000:02:00.0: SDB: 0000ce42:ff07fc47 WR-Periph-Syscon (00000000-000000ff)
FMC: mezzanine 0: 0000:02:00.0 on SPEC
FMC: poor dump of sdb first level:
0000: 53 44 42 2d 00 02 01 00 00 00 00 00 00 00 00 00
0010: 00 00 00 00 00 00 01 ff 00 00 00 00 00 00 06 51
0020: e6 a5 42 c9 00 00 00 02 20 12 05 11 57 42 34 2d
0030: 43 72 6f 73 73 62 61 72 2d 47 53 49 20 20 20 00
0040: 00 00 01 01 00 00 00 07 00 00 00 00 00 00 00 00
0050: 00 00 00 00 00 00 00 ff 00 00 00 00 00 00 ce 42
0060: ff 07 fc 47 00 00 00 01 20 12 03 05 57 52 2d 50
0070: 65 72 69 70 68 2d 53 79 73 63 6f 6e 20 20 20 01

View File

@ -11,6 +11,7 @@
* in the MontaVista 2.4 kernel (and the Amstrad changes therein)
*/
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@ -99,7 +100,8 @@ void __init ams_delta_init_fiq(struct gpio_chip *chip,
}
for (i = 0; i < ARRAY_SIZE(irq_data); i++) {
gpiod = gpiochip_request_own_desc(chip, i, pin_name[i], 0);
gpiod = gpiochip_request_own_desc(chip, i, pin_name[i],
GPIO_ACTIVE_HIGH, GPIOD_IN);
if (IS_ERR(gpiod)) {
pr_err("%s: failed to get GPIO pin %d (%ld)\n",
__func__, i, PTR_ERR(gpiod));

View File

@ -10,6 +10,7 @@
*/
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/init.h>
@ -606,12 +607,12 @@ static void __init modem_assign_irq(struct gpio_chip *chip)
struct gpio_desc *gpiod;
gpiod = gpiochip_request_own_desc(chip, AMS_DELTA_GPIO_PIN_MODEM_IRQ,
"modem_irq", 0);
"modem_irq", GPIO_ACTIVE_HIGH,
GPIOD_IN);
if (IS_ERR(gpiod)) {
pr_err("%s: modem IRQ GPIO request failed (%ld)\n", __func__,
PTR_ERR(gpiod));
} else {
gpiod_direction_input(gpiod);
ams_delta_modem_ports[0].irq = gpiod_to_irq(gpiod);
}
}

View File

@ -188,8 +188,6 @@ source "drivers/ipack/Kconfig"
source "drivers/reset/Kconfig"
source "drivers/fmc/Kconfig"
source "drivers/phy/Kconfig"
source "drivers/powercap/Kconfig"

View File

@ -168,7 +168,6 @@ obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_IPACK_BUS) += ipack/
obj-$(CONFIG_NTB) += ntb/
obj-$(CONFIG_FMC) += fmc/
obj-$(CONFIG_POWERCAP) += powercap/
obj-$(CONFIG_MCB) += mcb/
obj-$(CONFIG_PERF_EVENTS) += perf/

View File

@ -1,52 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# FMC (ANSI-VITA 57.1) bus support
#
menuconfig FMC
tristate "FMC support"
help
FMC (FPGA Mezzanine Carrier) is a mechanical and electrical
standard for mezzanine cards that plug into a carrier board.
This kernel subsystem supports the matching between carrier
and mezzanine based on identifiers stored in the internal I2C
EEPROM, as well as having carrier-independent drivers.
The framework was born outside of the kernel and at this time
the off-tree code base is more complete. Code and documentation
is at git://ohwr.org/fmc-projects/fmc-bus.git .
if FMC
config FMC_FAKEDEV
tristate "FMC fake device (software testing)"
help
This is a fake carrier, bringing a default EEPROM content
that can be rewritten at run time and usef for matching
mezzanines.
config FMC_TRIVIAL
tristate "FMC trivial mezzanine driver (software testing)"
help
This is a fake mezzanine driver, to show how FMC works and test it.
The driver also handles interrupts (we used it with a real carrier
before the mezzanines were produced)
config FMC_WRITE_EEPROM
tristate "FMC mezzanine driver to write I2C EEPROM"
help
This driver matches every mezzanine device and can write the
internal EEPROM of the PCB, using the firmware loader to get
its binary and the function carrier->reprogram to actually do it.
It is useful when the mezzanines are produced.
config FMC_CHARDEV
tristate "FMC mezzanine driver that registers a char device"
help
This driver matches every mezzanine device and allows user
space to read and write registers using a char device. It
can be used to write user-space drivers, or just get
acquainted with a mezzanine before writing its specific driver.
endif # FMC

View File

@ -1,15 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_FMC) += fmc.o
fmc-y = fmc-core.o
fmc-y += fmc-match.o
fmc-y += fmc-sdb.o
fmc-y += fru-parse.o
fmc-y += fmc-dump.o
fmc-y += fmc-debug.o
obj-$(CONFIG_FMC_FAKEDEV) += fmc-fakedev.o
obj-$(CONFIG_FMC_TRIVIAL) += fmc-trivial.o
obj-$(CONFIG_FMC_WRITE_EEPROM) += fmc-write-eeprom.o
obj-$(CONFIG_FMC_CHARDEV) += fmc-chardev.o

View File

@ -1,199 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/spinlock.h>
#include <linux/fmc.h>
#include <linux/uaccess.h>
static LIST_HEAD(fc_devices);
static DEFINE_SPINLOCK(fc_lock);
struct fc_instance {
struct list_head list;
struct fmc_device *fmc;
struct miscdevice misc;
};
/* at open time, we must identify our device */
static int fc_open(struct inode *ino, struct file *f)
{
struct fmc_device *fmc;
struct fc_instance *fc;
int minor = iminor(ino);
list_for_each_entry(fc, &fc_devices, list)
if (fc->misc.minor == minor)
break;
if (fc->misc.minor != minor)
return -ENODEV;
fmc = fc->fmc;
if (try_module_get(fmc->owner) == 0)
return -ENODEV;
f->private_data = fmc;
return 0;
}
static int fc_release(struct inode *ino, struct file *f)
{
struct fmc_device *fmc = f->private_data;
module_put(fmc->owner);
return 0;
}
/* read and write are simple after the default llseek has been used */
static ssize_t fc_read(struct file *f, char __user *buf, size_t count,
loff_t *offp)
{
struct fmc_device *fmc = f->private_data;
unsigned long addr;
uint32_t val;
if (count < sizeof(val))
return -EINVAL;
count = sizeof(val);
addr = *offp;
if (addr > fmc->memlen)
return -ESPIPE; /* Illegal seek */
val = fmc_readl(fmc, addr);
if (copy_to_user(buf, &val, count))
return -EFAULT;
*offp += count;
return count;
}
static ssize_t fc_write(struct file *f, const char __user *buf, size_t count,
loff_t *offp)
{
struct fmc_device *fmc = f->private_data;
unsigned long addr;
uint32_t val;
if (count < sizeof(val))
return -EINVAL;
count = sizeof(val);
addr = *offp;
if (addr > fmc->memlen)
return -ESPIPE; /* Illegal seek */
if (copy_from_user(&val, buf, count))
return -EFAULT;
fmc_writel(fmc, val, addr);
*offp += count;
return count;
}
static const struct file_operations fc_fops = {
.owner = THIS_MODULE,
.open = fc_open,
.release = fc_release,
.llseek = generic_file_llseek,
.read = fc_read,
.write = fc_write,
};
/* Device part .. */
static int fc_probe(struct fmc_device *fmc);
static int fc_remove(struct fmc_device *fmc);
static struct fmc_driver fc_drv = {
.version = FMC_VERSION,
.driver.name = KBUILD_MODNAME,
.probe = fc_probe,
.remove = fc_remove,
/* no table: we want to match everything */
};
/* We accept the generic busid parameter */
FMC_PARAM_BUSID(fc_drv);
/* probe and remove must allocate and release a misc device */
static int fc_probe(struct fmc_device *fmc)
{
int ret;
int index = 0;
struct fc_instance *fc;
index = fmc_validate(fmc, &fc_drv);
if (index < 0)
return -EINVAL; /* not our device: invalid */
/* Create a char device: we want to create it anew */
fc = kzalloc(sizeof(*fc), GFP_KERNEL);
if (!fc)
return -ENOMEM;
fc->fmc = fmc;
fc->misc.minor = MISC_DYNAMIC_MINOR;
fc->misc.fops = &fc_fops;
fc->misc.name = kstrdup(dev_name(&fmc->dev), GFP_KERNEL);
ret = misc_register(&fc->misc);
if (ret < 0)
goto out;
spin_lock(&fc_lock);
list_add(&fc->list, &fc_devices);
spin_unlock(&fc_lock);
dev_info(&fc->fmc->dev, "Created misc device \"%s\"\n",
fc->misc.name);
return 0;
out:
kfree(fc->misc.name);
kfree(fc);
return ret;
}
static int fc_remove(struct fmc_device *fmc)
{
struct fc_instance *fc;
list_for_each_entry(fc, &fc_devices, list)
if (fc->fmc == fmc)
break;
if (fc->fmc != fmc) {
dev_err(&fmc->dev, "remove called but not found\n");
return -ENODEV;
}
spin_lock(&fc_lock);
list_del(&fc->list);
spin_unlock(&fc_lock);
misc_deregister(&fc->misc);
kfree(fc->misc.name);
kfree(fc);
return 0;
}
static int fc_init(void)
{
int ret;
ret = fmc_driver_register(&fc_drv);
return ret;
}
static void fc_exit(void)
{
fmc_driver_unregister(&fc_drv);
}
module_init(fc_init);
module_exit(fc_exit);
MODULE_LICENSE("GPL");

View File

@ -1,388 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/fmc.h>
#include <linux/fmc-sdb.h>
#include "fmc-private.h"
static int fmc_check_version(unsigned long version, const char *name)
{
if (__FMC_MAJOR(version) != FMC_MAJOR) {
pr_err("%s: \"%s\" has wrong major (has %li, expected %i)\n",
__func__, name, __FMC_MAJOR(version), FMC_MAJOR);
return -EINVAL;
}
if (__FMC_MINOR(version) != FMC_MINOR)
pr_info("%s: \"%s\" has wrong minor (has %li, expected %i)\n",
__func__, name, __FMC_MINOR(version), FMC_MINOR);
return 0;
}
static int fmc_uevent(struct device *dev, struct kobj_uevent_env *env)
{
/* struct fmc_device *fdev = to_fmc_device(dev); */
/* FIXME: The MODALIAS */
add_uevent_var(env, "MODALIAS=%s", "fmc");
return 0;
}
static int fmc_probe(struct device *dev)
{
struct fmc_driver *fdrv = to_fmc_driver(dev->driver);
struct fmc_device *fdev = to_fmc_device(dev);
return fdrv->probe(fdev);
}
static int fmc_remove(struct device *dev)
{
struct fmc_driver *fdrv = to_fmc_driver(dev->driver);
struct fmc_device *fdev = to_fmc_device(dev);
return fdrv->remove(fdev);
}
static void fmc_shutdown(struct device *dev)
{
/* not implemented but mandatory */
}
static struct bus_type fmc_bus_type = {
.name = "fmc",
.match = fmc_match,
.uevent = fmc_uevent,
.probe = fmc_probe,
.remove = fmc_remove,
.shutdown = fmc_shutdown,
};
static void fmc_release(struct device *dev)
{
struct fmc_device *fmc = container_of(dev, struct fmc_device, dev);
kfree(fmc);
}
/*
* The eeprom is exported in sysfs, through a binary attribute
*/
static ssize_t fmc_read_eeprom(struct file *file, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev;
struct fmc_device *fmc;
int eelen;
dev = container_of(kobj, struct device, kobj);
fmc = container_of(dev, struct fmc_device, dev);
eelen = fmc->eeprom_len;
if (off > eelen)
return -ESPIPE;
if (off == eelen)
return 0; /* EOF */
if (off + count > eelen)
count = eelen - off;
memcpy(buf, fmc->eeprom + off, count);
return count;
}
static ssize_t fmc_write_eeprom(struct file *file, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev;
struct fmc_device *fmc;
dev = container_of(kobj, struct device, kobj);
fmc = container_of(dev, struct fmc_device, dev);
return fmc->op->write_ee(fmc, off, buf, count);
}
static struct bin_attribute fmc_eeprom_attr = {
.attr = { .name = "eeprom", .mode = S_IRUGO | S_IWUSR, },
.size = 8192, /* more or less standard */
.read = fmc_read_eeprom,
.write = fmc_write_eeprom,
};
int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h,
char *name, int flags)
{
if (fmc->op->irq_request)
return fmc->op->irq_request(fmc, h, name, flags);
return -EPERM;
}
EXPORT_SYMBOL(fmc_irq_request);
void fmc_irq_free(struct fmc_device *fmc)
{
if (fmc->op->irq_free)
fmc->op->irq_free(fmc);
}
EXPORT_SYMBOL(fmc_irq_free);
void fmc_irq_ack(struct fmc_device *fmc)
{
if (likely(fmc->op->irq_ack))
fmc->op->irq_ack(fmc);
}
EXPORT_SYMBOL(fmc_irq_ack);
int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv)
{
if (fmc->op->validate)
return fmc->op->validate(fmc, drv);
return -EPERM;
}
EXPORT_SYMBOL(fmc_validate);
int fmc_gpio_config(struct fmc_device *fmc, struct fmc_gpio *gpio, int ngpio)
{
if (fmc->op->gpio_config)
return fmc->op->gpio_config(fmc, gpio, ngpio);
return -EPERM;
}
EXPORT_SYMBOL(fmc_gpio_config);
int fmc_read_ee(struct fmc_device *fmc, int pos, void *d, int l)
{
if (fmc->op->read_ee)
return fmc->op->read_ee(fmc, pos, d, l);
return -EPERM;
}
EXPORT_SYMBOL(fmc_read_ee);
int fmc_write_ee(struct fmc_device *fmc, int pos, const void *d, int l)
{
if (fmc->op->write_ee)
return fmc->op->write_ee(fmc, pos, d, l);
return -EPERM;
}
EXPORT_SYMBOL(fmc_write_ee);
/*
* Functions for client modules follow
*/
int fmc_driver_register(struct fmc_driver *drv)
{
if (fmc_check_version(drv->version, drv->driver.name))
return -EINVAL;
drv->driver.bus = &fmc_bus_type;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL(fmc_driver_register);
void fmc_driver_unregister(struct fmc_driver *drv)
{
driver_unregister(&drv->driver);
}
EXPORT_SYMBOL(fmc_driver_unregister);
/*
* When a device set is registered, all eeproms must be read
* and all FRUs must be parsed
*/
int fmc_device_register_n_gw(struct fmc_device **devs, int n,
struct fmc_gateware *gw)
{
struct fmc_device *fmc, **devarray;
uint32_t device_id;
int i, ret = 0;
if (n < 1)
return 0;
/* Check the version of the first data structure (function prints) */
if (fmc_check_version(devs[0]->version, devs[0]->carrier_name))
return -EINVAL;
devarray = kmemdup(devs, n * sizeof(*devs), GFP_KERNEL);
if (!devarray)
return -ENOMEM;
/* Make all other checks before continuing, for all devices */
for (i = 0; i < n; i++) {
fmc = devarray[i];
if (!fmc->hwdev) {
pr_err("%s: device nr. %i has no hwdev pointer\n",
__func__, i);
ret = -EINVAL;
break;
}
if (fmc->flags & FMC_DEVICE_NO_MEZZANINE) {
dev_info(fmc->hwdev, "absent mezzanine in slot %d\n",
fmc->slot_id);
continue;
}
if (!fmc->eeprom) {
dev_err(fmc->hwdev, "no eeprom provided for slot %i\n",
fmc->slot_id);
ret = -EINVAL;
}
if (!fmc->eeprom_addr) {
dev_err(fmc->hwdev, "no eeprom_addr for slot %i\n",
fmc->slot_id);
ret = -EINVAL;
}
if (!fmc->carrier_name || !fmc->carrier_data ||
!fmc->device_id) {
dev_err(fmc->hwdev,
"device nr %i: carrier name, "
"data or dev_id not set\n", i);
ret = -EINVAL;
}
if (ret)
break;
}
if (ret) {
kfree(devarray);
return ret;
}
/* Validation is ok. Now init and register the devices */
for (i = 0; i < n; i++) {
fmc = devarray[i];
fmc->nr_slots = n; /* each slot must know how many are there */
fmc->devarray = devarray;
device_initialize(&fmc->dev);
fmc->dev.release = fmc_release;
fmc->dev.parent = fmc->hwdev;
/* Fill the identification stuff (may fail) */
fmc_fill_id_info(fmc);
fmc->dev.bus = &fmc_bus_type;
/* Name from mezzanine info or carrier info. Or 0,1,2.. */
device_id = fmc->device_id;
if (!fmc->mezzanine_name)
dev_set_name(&fmc->dev, "fmc-%04x", device_id);
else
dev_set_name(&fmc->dev, "%s-%04x", fmc->mezzanine_name,
device_id);
if (gw) {
/*
* The carrier already know the bitstream to load
* for this set of FMC mezzanines.
*/
ret = fmc->op->reprogram_raw(fmc, NULL,
gw->bitstream, gw->len);
if (ret) {
dev_warn(fmc->hwdev,
"Invalid gateware for FMC mezzanine\n");
goto out;
}
}
ret = device_add(&fmc->dev);
if (ret < 0) {
dev_err(fmc->hwdev, "Slot %i: Failed in registering "
"\"%s\"\n", fmc->slot_id, fmc->dev.kobj.name);
goto out;
}
ret = sysfs_create_bin_file(&fmc->dev.kobj, &fmc_eeprom_attr);
if (ret < 0) {
dev_err(&fmc->dev, "Failed in registering eeprom\n");
goto out1;
}
/* This device went well, give information to the user */
fmc_dump_eeprom(fmc);
fmc_debug_init(fmc);
}
return 0;
out1:
device_del(&fmc->dev);
out:
kfree(devarray);
for (i--; i >= 0; i--) {
fmc_debug_exit(devs[i]);
sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr);
device_del(&devs[i]->dev);
fmc_free_id_info(devs[i]);
put_device(&devs[i]->dev);
}
return ret;
}
EXPORT_SYMBOL(fmc_device_register_n_gw);
int fmc_device_register_n(struct fmc_device **devs, int n)
{
return fmc_device_register_n_gw(devs, n, NULL);
}
EXPORT_SYMBOL(fmc_device_register_n);
int fmc_device_register_gw(struct fmc_device *fmc, struct fmc_gateware *gw)
{
return fmc_device_register_n_gw(&fmc, 1, gw);
}
EXPORT_SYMBOL(fmc_device_register_gw);
int fmc_device_register(struct fmc_device *fmc)
{
return fmc_device_register_n(&fmc, 1);
}
EXPORT_SYMBOL(fmc_device_register);
void fmc_device_unregister_n(struct fmc_device **devs, int n)
{
int i;
if (n < 1)
return;
/* Free devarray first, not used by the later loop */
kfree(devs[0]->devarray);
for (i = 0; i < n; i++) {
fmc_debug_exit(devs[i]);
sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr);
device_del(&devs[i]->dev);
fmc_free_id_info(devs[i]);
put_device(&devs[i]->dev);
}
}
EXPORT_SYMBOL(fmc_device_unregister_n);
void fmc_device_unregister(struct fmc_device *fmc)
{
fmc_device_unregister_n(&fmc, 1);
}
EXPORT_SYMBOL(fmc_device_unregister);
/* Init and exit are trivial */
static int fmc_init(void)
{
return bus_register(&fmc_bus_type);
}
static void fmc_exit(void)
{
bus_unregister(&fmc_bus_type);
}
module_init(fmc_init);
module_exit(fmc_exit);
MODULE_LICENSE("GPL");

View File

@ -1,172 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2015 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <asm/byteorder.h>
#include <linux/fmc.h>
#include <linux/sdb.h>
#include <linux/fmc-sdb.h>
#define FMC_DBG_SDB_DUMP "dump_sdb"
static char *__strip_trailing_space(char *buf, char *str, int len)
{
int i = len - 1;
memcpy(buf, str, len);
buf[len] = '\0';
while (i >= 0 && buf[i] == ' ')
buf[i--] = '\0';
return buf;
}
#define __sdb_string(buf, field) ({ \
BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \
__strip_trailing_space(buf, (void *)(field), sizeof(field)); \
})
/**
* We do not check seq_printf() errors because we want to see things in any case
*/
static void fmc_sdb_dump_recursive(struct fmc_device *fmc, struct seq_file *s,
const struct sdb_array *arr)
{
unsigned long base = arr->baseaddr;
int i, j, n = arr->len, level = arr->level;
char tmp[64];
for (i = 0; i < n; i++) {
union sdb_record *r;
struct sdb_product *p;
struct sdb_component *c;
r = &arr->record[i];
c = &r->dev.sdb_component;
p = &c->product;
for (j = 0; j < level; j++)
seq_printf(s, " ");
switch (r->empty.record_type) {
case sdb_type_interconnect:
seq_printf(s, "%08llx:%08x %.19s\n",
__be64_to_cpu(p->vendor_id),
__be32_to_cpu(p->device_id),
p->name);
break;
case sdb_type_device:
seq_printf(s, "%08llx:%08x %.19s (%08llx-%08llx)\n",
__be64_to_cpu(p->vendor_id),
__be32_to_cpu(p->device_id),
p->name,
__be64_to_cpu(c->addr_first) + base,
__be64_to_cpu(c->addr_last) + base);
break;
case sdb_type_bridge:
seq_printf(s, "%08llx:%08x %.19s (bridge: %08llx)\n",
__be64_to_cpu(p->vendor_id),
__be32_to_cpu(p->device_id),
p->name,
__be64_to_cpu(c->addr_first) + base);
if (IS_ERR(arr->subtree[i])) {
seq_printf(s, "SDB: (bridge error %li)\n",
PTR_ERR(arr->subtree[i]));
break;
}
fmc_sdb_dump_recursive(fmc, s, arr->subtree[i]);
break;
case sdb_type_integration:
seq_printf(s, "integration\n");
break;
case sdb_type_repo_url:
seq_printf(s, "Synthesis repository: %s\n",
__sdb_string(tmp, r->repo_url.repo_url));
break;
case sdb_type_synthesis:
seq_printf(s, "Bitstream '%s' ",
__sdb_string(tmp, r->synthesis.syn_name));
seq_printf(s, "synthesized %08x by %s ",
__be32_to_cpu(r->synthesis.date),
__sdb_string(tmp, r->synthesis.user_name));
seq_printf(s, "(%s version %x), ",
__sdb_string(tmp, r->synthesis.tool_name),
__be32_to_cpu(r->synthesis.tool_version));
seq_printf(s, "commit %pm\n",
r->synthesis.commit_id);
break;
case sdb_type_empty:
seq_printf(s, "empty\n");
break;
default:
seq_printf(s, "UNKNOWN TYPE 0x%02x\n",
r->empty.record_type);
break;
}
}
}
static int fmc_sdb_dump(struct seq_file *s, void *offset)
{
struct fmc_device *fmc = s->private;
if (!fmc->sdb) {
seq_printf(s, "no SDB information\n");
return 0;
}
seq_printf(s, "FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev),
fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev));
/* Dump SDB information */
fmc_sdb_dump_recursive(fmc, s, fmc->sdb);
return 0;
}
static int fmc_sdb_dump_open(struct inode *inode, struct file *file)
{
struct fmc_device *fmc = inode->i_private;
return single_open(file, fmc_sdb_dump, fmc);
}
const struct file_operations fmc_dbgfs_sdb_dump = {
.owner = THIS_MODULE,
.open = fmc_sdb_dump_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
int fmc_debug_init(struct fmc_device *fmc)
{
fmc->dbg_dir = debugfs_create_dir(dev_name(&fmc->dev), NULL);
if (IS_ERR_OR_NULL(fmc->dbg_dir)) {
pr_err("FMC: Cannot create debugfs\n");
return PTR_ERR(fmc->dbg_dir);
}
fmc->dbg_sdb_dump = debugfs_create_file(FMC_DBG_SDB_DUMP, 0444,
fmc->dbg_dir, fmc,
&fmc_dbgfs_sdb_dump);
if (IS_ERR_OR_NULL(fmc->dbg_sdb_dump))
pr_err("FMC: Cannot create debugfs file %s\n",
FMC_DBG_SDB_DUMP);
return 0;
}
void fmc_debug_exit(struct fmc_device *fmc)
{
if (fmc->dbg_dir)
debugfs_remove_recursive(fmc->dbg_dir);
}

View File

@ -1,58 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/fmc.h>
#include <linux/fmc-sdb.h>
static int fmc_must_dump_eeprom;
module_param_named(dump_eeprom, fmc_must_dump_eeprom, int, 0644);
#define LINELEN 16
/* Dumping 8k takes oh so much: avoid duplicate lines */
static const uint8_t *dump_line(int addr, const uint8_t *line,
const uint8_t *prev)
{
int i;
if (!prev || memcmp(line, prev, LINELEN)) {
pr_info("%04x: ", addr);
for (i = 0; i < LINELEN; ) {
printk(KERN_CONT "%02x", line[i]);
i++;
printk(i & 3 ? " " : i & (LINELEN - 1) ? " " : "\n");
}
return line;
}
/* repeated line */
if (line == prev + LINELEN)
pr_info("[...]\n");
return prev;
}
void fmc_dump_eeprom(const struct fmc_device *fmc)
{
const uint8_t *line, *prev;
int i;
if (!fmc_must_dump_eeprom)
return;
pr_info("FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev),
fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev));
pr_info("FMC: dumping eeprom 0x%x (%i) bytes\n", fmc->eeprom_len,
fmc->eeprom_len);
line = fmc->eeprom;
prev = NULL;
for (i = 0; i < fmc->eeprom_len; i += LINELEN, line += LINELEN)
prev = dump_line(i, line, prev);
}

View File

@ -1,355 +0,0 @@
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* The software is provided "as is"; the copyright holders disclaim
* all warranties and liabilities, to the extent permitted by
* applicable law.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/firmware.h>
#include <linux/workqueue.h>
#include <linux/err.h>
#include <linux/fmc.h>
#define FF_EEPROM_SIZE 8192 /* The standard eeprom size */
#define FF_MAX_MEZZANINES 4 /* Fakes a multi-mezzanine carrier */
/* The user can pass up to 4 names of eeprom images to load */
static char *ff_eeprom[FF_MAX_MEZZANINES];
static int ff_nr_eeprom;
module_param_array_named(eeprom, ff_eeprom, charp, &ff_nr_eeprom, 0444);
/* The user can ask for a multi-mezzanine carrier, with the default eeprom */
static int ff_nr_dev = 1;
module_param_named(ndev, ff_nr_dev, int, 0444);
/* Lazily, don't support the "standard" module parameters */
/*
* Eeprom built from these commands:
../fru-generator -v fake-vendor -n fake-design-for-testing \
-s 01234 -p none > IPMI-FRU
gensdbfs . ../fake-eeprom.bin
*/
static char ff_eeimg[FF_MAX_MEZZANINES][FF_EEPROM_SIZE] = {
{
0x01, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0xf2, 0x01, 0x0b, 0x00, 0xb2,
0x86, 0x87, 0xcb, 0x66, 0x61, 0x6b, 0x65, 0x2d, 0x76, 0x65, 0x6e, 0x64,
0x6f, 0x72, 0xd7, 0x66, 0x61, 0x6b, 0x65, 0x2d, 0x64, 0x65, 0x73, 0x69,
0x67, 0x6e, 0x2d, 0x66, 0x6f, 0x72, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x69,
0x6e, 0x67, 0xc5, 0x30, 0x31, 0x32, 0x33, 0x34, 0xc4, 0x6e, 0x6f, 0x6e,
0x65, 0xda, 0x32, 0x30, 0x31, 0x32, 0x2d, 0x31, 0x31, 0x2d, 0x31, 0x39,
0x20, 0x32, 0x32, 0x3a, 0x34, 0x32, 0x3a, 0x33, 0x30, 0x2e, 0x30, 0x37,
0x34, 0x30, 0x35, 0x35, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
0x02, 0x02, 0x0d, 0xf7, 0xf8, 0x02, 0xb0, 0x04, 0x74, 0x04, 0xec, 0x04,
0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x02, 0x02, 0x0d, 0x5c, 0x93, 0x01,
0x4a, 0x01, 0x39, 0x01, 0x5a, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0b,
0x02, 0x02, 0x0d, 0x63, 0x8c, 0x00, 0xfa, 0x00, 0xed, 0x00, 0x06, 0x01,
0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x01, 0x02, 0x0d, 0xfb, 0xf5, 0x05,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x02, 0x0d, 0xfc, 0xf4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0d, 0xfd, 0xf3, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfa, 0x82, 0x0b, 0xea, 0x8f, 0xa2, 0x12, 0x00, 0x00, 0x1e, 0x44, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x53, 0x44, 0x42, 0x2d, 0x00, 0x03, 0x01, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xc4, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61,
0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x46, 0x69, 0x6c, 0x65,
0x44, 0x61, 0x74, 0x61, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf,
0x46, 0x69, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0x49, 0x50, 0x4d, 0x49,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, 0x50, 0x4d, 0x49,
0x2d, 0x46, 0x52, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x01, 0x66, 0x61, 0x6b, 0x65, 0x0a,
},
};
struct ff_dev {
struct fmc_device *fmc[FF_MAX_MEZZANINES];
struct device dev;
};
static struct ff_dev *ff_current_dev; /* We have 1 carrier, 1 slot */
static int ff_reprogram(struct fmc_device *fmc, struct fmc_driver *drv,
char *gw)
{
const struct firmware *fw;
int ret;
if (!gw) {
/* program golden: success */
fmc->flags &= ~FMC_DEVICE_HAS_CUSTOM;
fmc->flags |= FMC_DEVICE_HAS_GOLDEN;
return 0;
}
dev_info(&fmc->dev, "reprogramming with %s\n", gw);
ret = request_firmware(&fw, gw, &fmc->dev);
if (ret < 0) {
dev_warn(&fmc->dev, "request firmware \"%s\": error %i\n",
gw, ret);
goto out;
}
fmc->flags &= ~FMC_DEVICE_HAS_GOLDEN;
fmc->flags |= FMC_DEVICE_HAS_CUSTOM;
out:
release_firmware(fw);
return ret;
}
static int ff_irq_request(struct fmc_device *fmc, irq_handler_t handler,
char *name, int flags)
{
return -EOPNOTSUPP;
}
/* FIXME: should also have some fake FMC GPIO mapping */
/*
* This work function is called when we changed the eeprom. It removes the
* current fmc device and registers a new one, with different identifiers.
*/
static struct ff_dev *ff_dev_create(void); /* defined later */
static void ff_work_fn(struct work_struct *work)
{
struct ff_dev *ff = ff_current_dev;
int ret;
fmc_device_unregister_n(ff->fmc, ff_nr_dev);
device_unregister(&ff->dev);
ff_current_dev = NULL;
ff = ff_dev_create();
if (IS_ERR(ff)) {
pr_warning("%s: can't re-create FMC devices\n", __func__);
return;
}
ret = fmc_device_register_n(ff->fmc, ff_nr_dev);
if (ret < 0) {
dev_warn(&ff->dev, "can't re-register FMC devices\n");
device_unregister(&ff->dev);
return;
}
ff_current_dev = ff;
}
static DECLARE_DELAYED_WORK(ff_work, ff_work_fn);
/* low-level i2c */
static int ff_eeprom_read(struct fmc_device *fmc, uint32_t offset,
void *buf, size_t size)
{
if (offset > FF_EEPROM_SIZE)
return -EINVAL;
if (offset + size > FF_EEPROM_SIZE)
size = FF_EEPROM_SIZE - offset;
memcpy(buf, fmc->eeprom + offset, size);
return size;
}
static int ff_eeprom_write(struct fmc_device *fmc, uint32_t offset,
const void *buf, size_t size)
{
if (offset > FF_EEPROM_SIZE)
return -EINVAL;
if (offset + size > FF_EEPROM_SIZE)
size = FF_EEPROM_SIZE - offset;
dev_info(&fmc->dev, "write_eeprom: offset %i, size %zi\n",
(int)offset, size);
memcpy(fmc->eeprom + offset, buf, size);
schedule_delayed_work(&ff_work, HZ * 2); /* remove, replug, in 2s */
return size;
}
/* i2c operations for fmc */
static int ff_read_ee(struct fmc_device *fmc, int pos, void *data, int len)
{
if (!(fmc->flags & FMC_DEVICE_HAS_GOLDEN))
return -EOPNOTSUPP;
return ff_eeprom_read(fmc, pos, data, len);
}
static int ff_write_ee(struct fmc_device *fmc, int pos,
const void *data, int len)
{
if (!(fmc->flags & FMC_DEVICE_HAS_GOLDEN))
return -EOPNOTSUPP;
return ff_eeprom_write(fmc, pos, data, len);
}
/* readl and writel do not do anything. Don't waste RAM with "base" */
static uint32_t ff_readl(struct fmc_device *fmc, int offset)
{
return 0;
}
static void ff_writel(struct fmc_device *fmc, uint32_t value, int offset)
{
return;
}
/* validate is useful so fmc-write-eeprom will not reprogram every 2 seconds */
static int ff_validate(struct fmc_device *fmc, struct fmc_driver *drv)
{
int i;
if (!drv->busid_n)
return 0; /* everyhing is valid */
for (i = 0; i < drv->busid_n; i++)
if (drv->busid_val[i] == fmc->device_id)
return i;
return -ENOENT;
}
static struct fmc_operations ff_fmc_operations = {
.read32 = ff_readl,
.write32 = ff_writel,
.reprogram = ff_reprogram,
.irq_request = ff_irq_request,
.read_ee = ff_read_ee,
.write_ee = ff_write_ee,
.validate = ff_validate,
};
/* This device is kmalloced: release it */
static void ff_dev_release(struct device *dev)
{
struct ff_dev *ff = container_of(dev, struct ff_dev, dev);
kfree(ff);
}
static struct fmc_device ff_template_fmc = {
.version = FMC_VERSION,
.owner = THIS_MODULE,
.carrier_name = "fake-fmc-carrier",
.device_id = 0xf001, /* fool */
.eeprom_len = sizeof(ff_eeimg[0]),
.memlen = 0x1000, /* 4k, to show something */
.op = &ff_fmc_operations,
.hwdev = NULL, /* filled at creation time */
.flags = FMC_DEVICE_HAS_GOLDEN,
};
static struct ff_dev *ff_dev_create(void)
{
struct ff_dev *ff;
struct fmc_device *fmc;
int i, ret;
ff = kzalloc(sizeof(*ff), GFP_KERNEL);
if (!ff)
return ERR_PTR(-ENOMEM);
dev_set_name(&ff->dev, "fake-fmc-carrier");
ff->dev.release = ff_dev_release;
ret = device_register(&ff->dev);
if (ret < 0) {
put_device(&ff->dev);
return ERR_PTR(ret);
}
/* Create fmc structures that refer to this new "hw" device */
for (i = 0; i < ff_nr_dev; i++) {
fmc = kmemdup(&ff_template_fmc, sizeof(ff_template_fmc),
GFP_KERNEL);
fmc->hwdev = &ff->dev;
fmc->carrier_data = ff;
fmc->nr_slots = ff_nr_dev;
/* the following fields are different for each slot */
fmc->eeprom = ff_eeimg[i];
fmc->eeprom_addr = 0x50 + 2 * i;
fmc->slot_id = i;
ff->fmc[i] = fmc;
/* increment the identifier, each must be different */
ff_template_fmc.device_id++;
}
return ff;
}
/* init and exit */
static int ff_init(void)
{
struct ff_dev *ff;
const struct firmware *fw;
int i, len, ret = 0;
/* Replicate the default eeprom for the max number of mezzanines */
for (i = 1; i < FF_MAX_MEZZANINES; i++)
memcpy(ff_eeimg[i], ff_eeimg[0], sizeof(ff_eeimg[0]));
if (ff_nr_eeprom > ff_nr_dev)
ff_nr_dev = ff_nr_eeprom;
ff = ff_dev_create();
if (IS_ERR(ff))
return PTR_ERR(ff);
/* If the user passed "eeprom=" as a parameter, fetch them */
for (i = 0; i < ff_nr_eeprom; i++) {
if (!strlen(ff_eeprom[i]))
continue;
ret = request_firmware(&fw, ff_eeprom[i], &ff->dev);
if (ret < 0) {
dev_err(&ff->dev, "Mezzanine %i: can't load \"%s\" "
"(error %i)\n", i, ff_eeprom[i], -ret);
} else {
len = min_t(size_t, fw->size, (size_t)FF_EEPROM_SIZE);
memcpy(ff_eeimg[i], fw->data, len);
release_firmware(fw);
dev_info(&ff->dev, "Mezzanine %i: eeprom \"%s\"\n", i,
ff_eeprom[i]);
}
}
ret = fmc_device_register_n(ff->fmc, ff_nr_dev);
if (ret) {
device_unregister(&ff->dev);
return ret;
}
ff_current_dev = ff;
return ret;
}
static void ff_exit(void)
{
if (ff_current_dev) {
fmc_device_unregister_n(ff_current_dev->fmc, ff_nr_dev);
device_unregister(&ff_current_dev->dev);
}
cancel_delayed_work_sync(&ff_work);
}
module_init(ff_init);
module_exit(ff_exit);
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -1,113 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fmc.h>
#include <linux/ipmi-fru.h>
/* The fru parser is both user and kernel capable: it needs alloc */
void *fru_alloc(size_t size)
{
return kzalloc(size, GFP_KERNEL);
}
/* The actual match function */
int fmc_match(struct device *dev, struct device_driver *drv)
{
struct fmc_driver *fdrv = to_fmc_driver(drv);
struct fmc_device *fdev = to_fmc_device(dev);
struct fmc_fru_id *fid;
int i, matched = 0;
/* This currently only matches the EEPROM (FRU id) */
fid = fdrv->id_table.fru_id;
if (!fid) {
dev_warn(&fdev->dev, "Driver has no ID: matches all\n");
matched = 1;
} else {
if (!fdev->id.manufacturer || !fdev->id.product_name)
return 0; /* the device has no FRU information */
for (i = 0; i < fdrv->id_table.fru_id_nr; i++, fid++) {
if (fid->manufacturer &&
strcmp(fid->manufacturer, fdev->id.manufacturer))
continue;
if (fid->product_name &&
strcmp(fid->product_name, fdev->id.product_name))
continue;
matched = 1;
break;
}
}
/* FIXME: match SDB contents */
return matched;
}
/* This function creates ID info for a newly registered device */
int fmc_fill_id_info(struct fmc_device *fmc)
{
struct fru_common_header *h;
struct fru_board_info_area *bia;
int ret, allocated = 0;
/* If we know the eeprom length, try to read it off the device */
if (fmc->eeprom_len && !fmc->eeprom) {
fmc->eeprom = kzalloc(fmc->eeprom_len, GFP_KERNEL);
if (!fmc->eeprom)
return -ENOMEM;
allocated = 1;
ret = fmc_read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len);
if (ret < 0)
goto out;
}
/* If no eeprom, continue with other matches */
if (!fmc->eeprom)
return 0;
dev_info(fmc->hwdev, "mezzanine %i\n", fmc->slot_id); /* header */
/* So we have the eeprom: parse the FRU part (if any) */
h = (void *)fmc->eeprom;
if (h->format != 1) {
pr_info(" EEPROM has no FRU information\n");
goto out;
}
if (!fru_header_cksum_ok(h)) {
pr_info(" FRU: wrong header checksum\n");
goto out;
}
bia = fru_get_board_area(h);
if (!fru_bia_cksum_ok(bia)) {
pr_info(" FRU: wrong board area checksum\n");
goto out;
}
fmc->id.manufacturer = fru_get_board_manufacturer(h);
fmc->id.product_name = fru_get_product_name(h);
pr_info(" Manufacturer: %s\n", fmc->id.manufacturer);
pr_info(" Product name: %s\n", fmc->id.product_name);
/* Create the short name (FIXME: look in sdb as well) */
fmc->mezzanine_name = kstrdup(fmc->id.product_name, GFP_KERNEL);
out:
if (allocated) {
kfree(fmc->eeprom);
fmc->eeprom = NULL;
}
return 0; /* no error: let other identification work */
}
/* Some ID data is allocated using fru_alloc() above, so release it */
void fmc_free_id_info(struct fmc_device *fmc)
{
kfree(fmc->mezzanine_name);
kfree(fmc->id.manufacturer);
kfree(fmc->id.product_name);
}

View File

@ -1,8 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2015 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
extern int fmc_debug_init(struct fmc_device *fmc);
extern void fmc_debug_exit(struct fmc_device *fmc);

View File

@ -1,219 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fmc.h>
#include <linux/sdb.h>
#include <linux/err.h>
#include <linux/fmc-sdb.h>
#include <asm/byteorder.h>
static uint32_t __sdb_rd(struct fmc_device *fmc, unsigned long address,
int convert)
{
uint32_t res = fmc_readl(fmc, address);
if (convert)
return __be32_to_cpu(res);
return res;
}
static struct sdb_array *__fmc_scan_sdb_tree(struct fmc_device *fmc,
unsigned long sdb_addr,
unsigned long reg_base, int level)
{
uint32_t onew;
int i, j, n, convert = 0;
struct sdb_array *arr, *sub;
onew = fmc_readl(fmc, sdb_addr);
if (onew == SDB_MAGIC) {
/* Uh! If we are little-endian, we must convert */
if (SDB_MAGIC != __be32_to_cpu(SDB_MAGIC))
convert = 1;
} else if (onew == __be32_to_cpu(SDB_MAGIC)) {
/* ok, don't convert */
} else {
return ERR_PTR(-ENOENT);
}
/* So, the magic was there: get the count from offset 4*/
onew = __sdb_rd(fmc, sdb_addr + 4, convert);
n = __be16_to_cpu(*(uint16_t *)&onew);
arr = kzalloc(sizeof(*arr), GFP_KERNEL);
if (!arr)
return ERR_PTR(-ENOMEM);
arr->record = kcalloc(n, sizeof(arr->record[0]), GFP_KERNEL);
arr->subtree = kcalloc(n, sizeof(arr->subtree[0]), GFP_KERNEL);
if (!arr->record || !arr->subtree) {
kfree(arr->record);
kfree(arr->subtree);
kfree(arr);
return ERR_PTR(-ENOMEM);
}
arr->len = n;
arr->level = level;
arr->fmc = fmc;
for (i = 0; i < n; i++) {
union sdb_record *r;
for (j = 0; j < sizeof(arr->record[0]); j += 4) {
*(uint32_t *)((void *)(arr->record + i) + j) =
__sdb_rd(fmc, sdb_addr + (i * 64) + j, convert);
}
r = &arr->record[i];
arr->subtree[i] = ERR_PTR(-ENODEV);
if (r->empty.record_type == sdb_type_bridge) {
struct sdb_component *c = &r->bridge.sdb_component;
uint64_t subaddr = __be64_to_cpu(r->bridge.sdb_child);
uint64_t newbase = __be64_to_cpu(c->addr_first);
subaddr += reg_base;
newbase += reg_base;
sub = __fmc_scan_sdb_tree(fmc, subaddr, newbase,
level + 1);
arr->subtree[i] = sub; /* may be error */
if (IS_ERR(sub))
continue;
sub->parent = arr;
sub->baseaddr = newbase;
}
}
return arr;
}
int fmc_scan_sdb_tree(struct fmc_device *fmc, unsigned long address)
{
struct sdb_array *ret;
if (fmc->sdb)
return -EBUSY;
ret = __fmc_scan_sdb_tree(fmc, address, 0 /* regs */, 0);
if (IS_ERR(ret))
return PTR_ERR(ret);
fmc->sdb = ret;
return 0;
}
EXPORT_SYMBOL(fmc_scan_sdb_tree);
static void __fmc_sdb_free(struct sdb_array *arr)
{
int i, n;
if (!arr)
return;
n = arr->len;
for (i = 0; i < n; i++) {
if (IS_ERR(arr->subtree[i]))
continue;
__fmc_sdb_free(arr->subtree[i]);
}
kfree(arr->record);
kfree(arr->subtree);
kfree(arr);
}
int fmc_free_sdb_tree(struct fmc_device *fmc)
{
__fmc_sdb_free(fmc->sdb);
fmc->sdb = NULL;
return 0;
}
EXPORT_SYMBOL(fmc_free_sdb_tree);
/* This helper calls reprogram and inizialized sdb as well */
int fmc_reprogram_raw(struct fmc_device *fmc, struct fmc_driver *d,
void *gw, unsigned long len, int sdb_entry)
{
int ret;
ret = fmc->op->reprogram_raw(fmc, d, gw, len);
if (ret < 0)
return ret;
if (sdb_entry < 0)
return ret;
/* We are required to find SDB at a given offset */
ret = fmc_scan_sdb_tree(fmc, sdb_entry);
if (ret < 0) {
dev_err(&fmc->dev, "Can't find SDB at address 0x%x\n",
sdb_entry);
return -ENODEV;
}
return 0;
}
EXPORT_SYMBOL(fmc_reprogram_raw);
/* This helper calls reprogram and inizialized sdb as well */
int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw,
int sdb_entry)
{
int ret;
ret = fmc->op->reprogram(fmc, d, gw);
if (ret < 0)
return ret;
if (sdb_entry < 0)
return ret;
/* We are required to find SDB at a given offset */
ret = fmc_scan_sdb_tree(fmc, sdb_entry);
if (ret < 0) {
dev_err(&fmc->dev, "Can't find SDB at address 0x%x\n",
sdb_entry);
return -ENODEV;
}
return 0;
}
EXPORT_SYMBOL(fmc_reprogram);
void fmc_show_sdb_tree(const struct fmc_device *fmc)
{
pr_err("%s: not supported anymore, use debugfs to dump SDB\n",
__func__);
}
EXPORT_SYMBOL(fmc_show_sdb_tree);
signed long fmc_find_sdb_device(struct sdb_array *tree,
uint64_t vid, uint32_t did, unsigned long *sz)
{
signed long res = -ENODEV;
union sdb_record *r;
struct sdb_product *p;
struct sdb_component *c;
int i, n = tree->len;
uint64_t last, first;
/* FIXME: what if the first interconnect is not at zero? */
for (i = 0; i < n; i++) {
r = &tree->record[i];
c = &r->dev.sdb_component;
p = &c->product;
if (!IS_ERR(tree->subtree[i]))
res = fmc_find_sdb_device(tree->subtree[i],
vid, did, sz);
if (res >= 0)
return res + tree->baseaddr;
if (r->empty.record_type != sdb_type_device)
continue;
if (__be64_to_cpu(p->vendor_id) != vid)
continue;
if (__be32_to_cpu(p->device_id) != did)
continue;
/* found */
last = __be64_to_cpu(c->addr_last);
first = __be64_to_cpu(c->addr_first);
if (sz)
*sz = (typeof(*sz))(last + 1 - first);
return first + tree->baseaddr;
}
return res;
}
EXPORT_SYMBOL(fmc_find_sdb_device);

View File

@ -1,103 +0,0 @@
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* The software is provided "as is"; the copyright holders disclaim
* all warranties and liabilities, to the extent permitted by
* applicable law.
*/
/* A trivial fmc driver that can load a gateware file and reports interrupts */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/fmc.h>
static struct fmc_driver t_drv; /* initialized later */
static irqreturn_t t_handler(int irq, void *dev_id)
{
struct fmc_device *fmc = dev_id;
fmc_irq_ack(fmc);
dev_info(&fmc->dev, "received irq %i\n", irq);
return IRQ_HANDLED;
}
static struct fmc_gpio t_gpio[] = {
{
.gpio = FMC_GPIO_IRQ(0),
.mode = GPIOF_DIR_IN,
.irqmode = IRQF_TRIGGER_RISING,
}, {
.gpio = FMC_GPIO_IRQ(1),
.mode = GPIOF_DIR_IN,
.irqmode = IRQF_TRIGGER_RISING,
}
};
static int t_probe(struct fmc_device *fmc)
{
int ret;
int index = 0;
index = fmc_validate(fmc, &t_drv);
if (index < 0)
return -EINVAL; /* not our device: invalid */
ret = fmc_irq_request(fmc, t_handler, "fmc-trivial", IRQF_SHARED);
if (ret < 0)
return ret;
/* ignore error code of call below, we really don't care */
fmc_gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio));
ret = fmc_reprogram(fmc, &t_drv, "", 0);
if (ret == -EPERM) /* programming not supported */
ret = 0;
if (ret < 0)
fmc_irq_free(fmc);
/* FIXME: reprogram LM32 too */
return ret;
}
static int t_remove(struct fmc_device *fmc)
{
fmc_irq_free(fmc);
return 0;
}
static struct fmc_driver t_drv = {
.version = FMC_VERSION,
.driver.name = KBUILD_MODNAME,
.probe = t_probe,
.remove = t_remove,
/* no table, as the current match just matches everything */
};
/* We accept the generic parameters */
FMC_PARAM_BUSID(t_drv);
FMC_PARAM_GATEWARE(t_drv);
static int t_init(void)
{
int ret;
ret = fmc_driver_register(&t_drv);
return ret;
}
static void t_exit(void)
{
fmc_driver_unregister(&t_drv);
}
module_init(t_init);
module_exit(t_exit);
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -1,175 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <linux/module.h>
#include <linux/string.h>
#include <linux/firmware.h>
#include <linux/init.h>
#include <linux/fmc.h>
#include <asm/unaligned.h>
/*
* This module uses the firmware loader to program the whole or part
* of the FMC eeprom. The meat is in the _run functions. However, no
* default file name is provided, to avoid accidental mishaps. Also,
* you must pass the busid argument
*/
static struct fmc_driver fwe_drv;
FMC_PARAM_BUSID(fwe_drv);
/* The "file=" is like the generic "gateware=" used elsewhere */
static char *fwe_file[FMC_MAX_CARDS];
static int fwe_file_n;
module_param_array_named(file, fwe_file, charp, &fwe_file_n, 0444);
static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw,
int write)
{
const uint8_t *p = fw->data;
int len = fw->size;
uint16_t thislen, thisaddr;
int err;
/* format is: 'w' addr16 len16 data... */
while (len > 5) {
thisaddr = get_unaligned_le16(p+1);
thislen = get_unaligned_le16(p+3);
if (p[0] != 'w' || thislen + 5 > len) {
dev_err(&fmc->dev, "invalid tlv at offset %ti\n",
p - fw->data);
return -EINVAL;
}
err = 0;
if (write) {
dev_info(&fmc->dev, "write %i bytes at 0x%04x\n",
thislen, thisaddr);
err = fmc_write_ee(fmc, thisaddr, p + 5, thislen);
}
if (err < 0) {
dev_err(&fmc->dev, "write failure @0x%04x\n",
thisaddr);
return err;
}
p += 5 + thislen;
len -= 5 + thislen;
}
if (write)
dev_info(&fmc->dev, "write_eeprom: success\n");
return 0;
}
static int fwe_run_bin(struct fmc_device *fmc, const struct firmware *fw)
{
int ret;
dev_info(&fmc->dev, "programming %zi bytes\n", fw->size);
ret = fmc_write_ee(fmc, 0, (void *)fw->data, fw->size);
if (ret < 0) {
dev_info(&fmc->dev, "write_eeprom: error %i\n", ret);
return ret;
}
dev_info(&fmc->dev, "write_eeprom: success\n");
return 0;
}
static int fwe_run(struct fmc_device *fmc, const struct firmware *fw, char *s)
{
char *last4 = s + strlen(s) - 4;
int err;
if (!strcmp(last4, ".bin"))
return fwe_run_bin(fmc, fw);
if (!strcmp(last4, ".tlv")) {
err = fwe_run_tlv(fmc, fw, 0);
if (!err)
err = fwe_run_tlv(fmc, fw, 1);
return err;
}
dev_err(&fmc->dev, "invalid file name \"%s\"\n", s);
return -EINVAL;
}
/*
* Programming is done at probe time. Morever, only those listed with
* busid= are programmed.
* card is probed for, only one is programmed. Unfortunately, it's
* difficult to know in advance when probing the first card if others
* are there.
*/
static int fwe_probe(struct fmc_device *fmc)
{
int err, index = 0;
const struct firmware *fw;
struct device *dev = &fmc->dev;
char *s;
if (!fwe_drv.busid_n) {
dev_err(dev, "%s: no busid passed, refusing all cards\n",
KBUILD_MODNAME);
return -ENODEV;
}
index = fmc_validate(fmc, &fwe_drv);
if (index < 0) {
pr_err("%s: refusing device \"%s\"\n", KBUILD_MODNAME,
dev_name(dev));
return -ENODEV;
}
if (index >= fwe_file_n) {
pr_err("%s: no filename for device index %i\n",
KBUILD_MODNAME, index);
return -ENODEV;
}
s = fwe_file[index];
if (!s) {
pr_err("%s: no filename for \"%s\" not programming\n",
KBUILD_MODNAME, dev_name(dev));
return -ENOENT;
}
err = request_firmware(&fw, s, dev);
if (err < 0) {
dev_err(&fmc->dev, "request firmware \"%s\": error %i\n",
s, err);
return err;
}
fwe_run(fmc, fw, s);
release_firmware(fw);
return 0;
}
static int fwe_remove(struct fmc_device *fmc)
{
return 0;
}
static struct fmc_driver fwe_drv = {
.version = FMC_VERSION,
.driver.name = KBUILD_MODNAME,
.probe = fwe_probe,
.remove = fwe_remove,
/* no table, as the current match just matches everything */
};
static int fwe_init(void)
{
int ret;
ret = fmc_driver_register(&fwe_drv);
return ret;
}
static void fwe_exit(void)
{
fmc_driver_unregister(&fwe_drv);
}
module_init(fwe_init);
module_exit(fwe_exit);
MODULE_LICENSE("GPL");

View File

@ -1,80 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <linux/ipmi-fru.h>
/* Some internal helpers */
static struct fru_type_length *
__fru_get_board_tl(struct fru_common_header *header, int nr)
{
struct fru_board_info_area *bia;
struct fru_type_length *tl;
bia = fru_get_board_area(header);
tl = bia->tl;
while (nr > 0 && !fru_is_eof(tl)) {
tl = fru_next_tl(tl);
nr--;
}
if (fru_is_eof(tl))
return NULL;
return tl;
}
static char *__fru_alloc_get_tl(struct fru_common_header *header, int nr)
{
struct fru_type_length *tl;
char *res;
tl = __fru_get_board_tl(header, nr);
if (!tl)
return NULL;
res = fru_alloc(fru_strlen(tl) + 1);
if (!res)
return NULL;
return fru_strcpy(res, tl);
}
/* Public checksum verifiers */
int fru_header_cksum_ok(struct fru_common_header *header)
{
uint8_t *ptr = (void *)header;
int i, sum;
for (i = sum = 0; i < sizeof(*header); i++)
sum += ptr[i];
return (sum & 0xff) == 0;
}
int fru_bia_cksum_ok(struct fru_board_info_area *bia)
{
uint8_t *ptr = (void *)bia;
int i, sum;
for (i = sum = 0; i < 8 * bia->area_len; i++)
sum += ptr[i];
return (sum & 0xff) == 0;
}
/* Get various stuff, trivial */
char *fru_get_board_manufacturer(struct fru_common_header *header)
{
return __fru_alloc_get_tl(header, 0);
}
char *fru_get_product_name(struct fru_common_header *header)
{
return __fru_alloc_get_tl(header, 1);
}
char *fru_get_serial_number(struct fru_common_header *header)
{
return __fru_alloc_get_tl(header, 2);
}
char *fru_get_part_number(struct fru_common_header *header)
{
return __fru_alloc_get_tl(header, 3);
}

View File

@ -62,16 +62,12 @@ config GPIO_SYSFS
bool "/sys/class/gpio/... (sysfs interface)"
depends on SYSFS
help
Say Y here to add a sysfs interface for GPIOs.
Say Y here to add the legacy sysfs interface for GPIOs.
This is mostly useful to work around omissions in a system's
kernel support. Those are common in custom and semicustom
hardware assembled using standard kernels with a minimum of
custom patches. In those cases, userspace code may import
a given GPIO from the kernel, if no kernel driver requested it.
Kernel drivers may also request that a particular GPIO be
exported to userspace; this can be useful when debugging.
This ABI is deprecated. If you want to use GPIO from userspace,
use the character device /dev/gpiochipN with the appropriate
ioctl() operations instead. The character device is always
available.
config GPIO_GENERIC
depends on HAS_IOMEM # Only for IOMEM drivers
@ -178,7 +174,7 @@ config GPIO_CLPS711X
config GPIO_DAVINCI
bool "TI Davinci/Keystone GPIO support"
default y if ARCH_DAVINCI
depends on ARM && (ARCH_DAVINCI || ARCH_KEYSTONE)
depends on (ARM || ARM64) && (ARCH_DAVINCI || ARCH_KEYSTONE || ARCH_K3)
help
Say yes here to enable GPIO support for TI Davinci/Keystone SoCs.
@ -493,7 +489,8 @@ config GPIO_STA2X11
config GPIO_STP_XWAY
bool "XWAY STP GPIOs"
depends on SOC_XWAY
depends on SOC_XWAY || COMPILE_TEST
depends on OF_GPIO
help
This enables support for the Serial To Parallel (STP) unit found on
XWAY SoC. The STP allows the SoC to drive a shift registers cascade,
@ -602,7 +599,6 @@ config GPIO_XGENE_SB
config GPIO_XILINX
tristate "Xilinx GPIO support"
depends on OF_GPIO
help
Say yes here to support the Xilinx FPGA GPIO device

View File

@ -17,154 +17,154 @@ obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
# directly supported by gpio-generic
gpio-generic-$(CONFIG_GPIO_GENERIC) += gpio-mmio.o
obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o
obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o
obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o
obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o
obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o
obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o
obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o
obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o
obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o
obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o
obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o
obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o
obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o
obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o
obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o
obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o
obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o
obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o
obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o
obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o
obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o
obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o
obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o
obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o
obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o
obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o
obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o
obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o
obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o
obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o
obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
obj-$(CONFIG_GPIO_REG) += gpio-reg.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_GPIO_REG) += gpio-reg.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o
obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o
obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o
obj-$(CONFIG_GPIO_TQMX86) += gpio-tqmx86.o
obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o
obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o
obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o
obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_WS16C48) += gpio-ws16c48.o
obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o
obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
obj-$(CONFIG_GPIO_ZX) += gpio-zx.o
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o
obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o
obj-$(CONFIG_GPIO_TQMX86) += gpio-tqmx86.o
obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o
obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o
obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o
obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_WS16C48) += gpio-ws16c48.o
obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o
obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
obj-$(CONFIG_GPIO_ZX) += gpio-zx.o
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o

View File

@ -90,6 +90,46 @@ GPIOLIB irqchip
The GPIOLIB irqchip is a helper irqchip for "simple cases" that should
try to cover any generic kind of irqchip cascaded from a GPIO.
- Convert all the GPIOLIB_IRQCHIP users to pass an irqchip template,
parent and flags before calling [devm_]gpiochip_add[_data]().
Currently we set up the irqchip after setting up the gpiochip
using gpiochip_irqchip_add() and gpiochip_set_[chained|nested]_irqchip().
This is too complex, so convert all users over to just set up
the irqchip before registering the gpio_chip, typical example:
/* Typical state container with dynamic irqchip */
struct my_gpio {
struct gpio_chip gc;
struct irq_chip irq;
};
int irq; /* from platform etc */
struct my_gpio *g;
struct gpio_irq_chip *girq
/* Set up the irqchip dynamically */
g->irq.name = "my_gpio_irq";
g->irq.irq_ack = my_gpio_ack_irq;
g->irq.irq_mask = my_gpio_mask_irq;
g->irq.irq_unmask = my_gpio_unmask_irq;
g->irq.irq_set_type = my_gpio_set_irq_type;
/* Get a pointer to the gpio_irq_chip */
girq = &g->gc.irq;
girq->chip = &g->irq;
girq->parent_handler = ftgpio_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
girq->parents[0] = irq;
When this is done, we will delete the old APIs for instatiating
GPIOLIB_IRQCHIP and simplify the code.
- Look over and identify any remaining easily converted drivers and
dry-code conversions to gpiolib irqchip for maintainers to test

View File

@ -30,6 +30,7 @@ struct altera_gpio_chip {
raw_spinlock_t gpio_lock;
int interrupt_trigger;
int mapped_irq;
struct irq_chip irq_chip;
};
static void altera_gpio_irq_unmask(struct irq_data *d)
@ -101,15 +102,6 @@ static unsigned int altera_gpio_irq_startup(struct irq_data *d)
return 0;
}
static struct irq_chip altera_irq_chip = {
.name = "altera-gpio",
.irq_mask = altera_gpio_irq_mask,
.irq_unmask = altera_gpio_irq_unmask,
.irq_set_type = altera_gpio_irq_set_type,
.irq_startup = altera_gpio_irq_startup,
.irq_shutdown = altera_gpio_irq_mask,
};
static int altera_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct of_mm_gpio_chip *mm_gc;
@ -246,6 +238,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
int reg, ret;
struct altera_gpio_chip *altera_gc;
struct gpio_irq_chip *girq;
altera_gc = devm_kzalloc(&pdev->dev, sizeof(*altera_gc), GFP_KERNEL);
if (!altera_gc)
@ -273,6 +266,41 @@ static int altera_gpio_probe(struct platform_device *pdev)
altera_gc->mmchip.gc.owner = THIS_MODULE;
altera_gc->mmchip.gc.parent = &pdev->dev;
altera_gc->mapped_irq = platform_get_irq(pdev, 0);
if (altera_gc->mapped_irq < 0)
goto skip_irq;
if (of_property_read_u32(node, "altr,interrupt-type", &reg)) {
dev_err(&pdev->dev,
"altr,interrupt-type value not set in device tree\n");
return -EINVAL;
}
altera_gc->interrupt_trigger = reg;
altera_gc->irq_chip.name = "altera-gpio";
altera_gc->irq_chip.irq_mask = altera_gpio_irq_mask;
altera_gc->irq_chip.irq_unmask = altera_gpio_irq_unmask;
altera_gc->irq_chip.irq_set_type = altera_gpio_irq_set_type;
altera_gc->irq_chip.irq_startup = altera_gpio_irq_startup;
altera_gc->irq_chip.irq_shutdown = altera_gpio_irq_mask;
girq = &altera_gc->mmchip.gc.irq;
girq->chip = &altera_gc->irq_chip;
if (altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
girq->parent_handler = altera_gpio_irq_leveL_high_handler;
else
girq->parent_handler = altera_gpio_irq_edge_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
girq->parents[0] = altera_gc->mapped_irq;
skip_irq:
ret = of_mm_gpiochip_add_data(node, &altera_gc->mmchip, altera_gc);
if (ret) {
dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
@ -281,42 +309,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, altera_gc);
altera_gc->mapped_irq = platform_get_irq(pdev, 0);
if (altera_gc->mapped_irq < 0)
goto skip_irq;
if (of_property_read_u32(node, "altr,interrupt-type", &reg)) {
ret = -EINVAL;
dev_err(&pdev->dev,
"altr,interrupt-type value not set in device tree\n");
goto teardown;
}
altera_gc->interrupt_trigger = reg;
ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0,
handle_bad_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(&pdev->dev, "could not add irqchip\n");
goto teardown;
}
gpiochip_set_chained_irqchip(&altera_gc->mmchip.gc,
&altera_irq_chip,
altera_gc->mapped_irq,
altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH ?
altera_gpio_irq_leveL_high_handler :
altera_gpio_irq_edge_handler);
skip_irq:
return 0;
teardown:
of_mm_gpiochip_remove(&altera_gc->mmchip);
pr_err("%pOF: registration failed with status %d\n",
node, ret);
return ret;
}
static int altera_gpio_remove(struct platform_device *pdev)

View File

@ -25,14 +25,13 @@
#define AMD_FCH_GPIO_FLAG_WRITE BIT(22)
#define AMD_FCH_GPIO_FLAG_READ BIT(16)
static struct resource amd_fch_gpio_iores =
static const struct resource amd_fch_gpio_iores =
DEFINE_RES_MEM_NAMED(
AMD_FCH_MMIO_BASE + AMD_FCH_GPIO_BANK0_BASE,
AMD_FCH_GPIO_SIZE,
"amd-fch-gpio-iomem");
struct amd_fch_gpio_priv {
struct platform_device *pdev;
struct gpio_chip gc;
void __iomem *base;
struct amd_fch_gpio_pdata *pdata;
@ -153,7 +152,6 @@ static int amd_fch_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
priv->pdata = pdata;
priv->pdev = pdev;
priv->gc.owner = THIS_MODULE;
priv->gc.parent = &pdev->dev;

View File

@ -88,7 +88,7 @@ static int pt_gpio_probe(struct platform_device *pdev)
pt_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pt_gpio->reg_base)) {
dev_err(&pdev->dev, "Failed to map MMIO resource for PT GPIO.\n");
dev_err(dev, "Failed to map MMIO resource for PT GPIO.\n");
return PTR_ERR(pt_gpio->reg_base);
}
@ -98,7 +98,7 @@ static int pt_gpio_probe(struct platform_device *pdev)
pt_gpio->reg_base + PT_DIRECTION_REG, NULL,
BGPIOF_READ_OUTPUT_REG_SET);
if (ret) {
dev_err(&pdev->dev, "bgpio_init failed\n");
dev_err(dev, "bgpio_init failed\n");
return ret;
}
@ -107,11 +107,11 @@ static int pt_gpio_probe(struct platform_device *pdev)
pt_gpio->gc.free = pt_gpio_free;
pt_gpio->gc.ngpio = PT_TOTAL_GPIO;
#if defined(CONFIG_OF_GPIO)
pt_gpio->gc.of_node = pdev->dev.of_node;
pt_gpio->gc.of_node = dev->of_node;
#endif
ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio);
if (ret) {
dev_err(&pdev->dev, "Failed to register GPIO lib\n");
dev_err(dev, "Failed to register GPIO lib\n");
return ret;
}
@ -121,7 +121,7 @@ static int pt_gpio_probe(struct platform_device *pdev)
writel(0, pt_gpio->reg_base + PT_SYNC_REG);
writel(0, pt_gpio->reg_base + PT_CLOCKRATE_REG);
dev_dbg(&pdev->dev, "PT GPIO driver loaded\n");
dev_dbg(dev, "PT GPIO driver loaded\n");
return ret;
}

View File

@ -222,14 +222,16 @@ MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
static int ath79_gpio_probe(struct platform_device *pdev)
{
struct ath79_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct ath79_gpio_ctrl *ctrl;
struct gpio_irq_chip *girq;
struct resource *res;
u32 ath79_gpio_count;
bool oe_inverted;
int err;
ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return -ENOMEM;
platform_set_drvdata(pdev, ctrl);
@ -237,7 +239,7 @@ static int ath79_gpio_probe(struct platform_device *pdev)
if (np) {
err = of_property_read_u32(np, "ngpios", &ath79_gpio_count);
if (err) {
dev_err(&pdev->dev, "ngpios property is not valid\n");
dev_err(dev, "ngpios property is not valid\n");
return err;
}
oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio");
@ -245,25 +247,24 @@ static int ath79_gpio_probe(struct platform_device *pdev)
ath79_gpio_count = pdata->ngpios;
oe_inverted = pdata->oe_inverted;
} else {
dev_err(&pdev->dev, "No DT node or platform data found\n");
dev_err(dev, "No DT node or platform data found\n");
return -EINVAL;
}
if (ath79_gpio_count >= 32) {
dev_err(&pdev->dev, "ngpios must be less than 32\n");
dev_err(dev, "ngpios must be less than 32\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
ctrl->base = devm_ioremap_nocache(
&pdev->dev, res->start, resource_size(res));
ctrl->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!ctrl->base)
return -ENOMEM;
raw_spin_lock_init(&ctrl->lock);
err = bgpio_init(&ctrl->gc, &pdev->dev, 4,
err = bgpio_init(&ctrl->gc, dev, 4,
ctrl->base + AR71XX_GPIO_REG_IN,
ctrl->base + AR71XX_GPIO_REG_SET,
ctrl->base + AR71XX_GPIO_REG_CLEAR,
@ -271,45 +272,33 @@ static int ath79_gpio_probe(struct platform_device *pdev)
oe_inverted ? ctrl->base + AR71XX_GPIO_REG_OE : NULL,
0);
if (err) {
dev_err(&pdev->dev, "bgpio_init failed\n");
dev_err(dev, "bgpio_init failed\n");
return err;
}
/* Use base 0 to stay compatible with legacy platforms */
ctrl->gc.base = 0;
err = gpiochip_add_data(&ctrl->gc, ctrl);
/* Optional interrupt setup */
if (!np || of_property_read_bool(np, "interrupt-controller")) {
girq = &ctrl->gc.irq;
girq->chip = &ath79_gpio_irqchip;
girq->parent_handler = ath79_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
girq->parents[0] = platform_get_irq(pdev, 0);
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_simple_irq;
}
err = devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
if (err) {
dev_err(&pdev->dev,
dev_err(dev,
"cannot add AR71xx GPIO chip, error=%d", err);
return err;
}
if (np && !of_property_read_bool(np, "interrupt-controller"))
return 0;
err = gpiochip_irqchip_add(&ctrl->gc, &ath79_gpio_irqchip, 0,
handle_simple_irq, IRQ_TYPE_NONE);
if (err) {
dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n");
goto gpiochip_remove;
}
gpiochip_set_chained_irqchip(&ctrl->gc, &ath79_gpio_irqchip,
platform_get_irq(pdev, 0),
ath79_gpio_irq_handler);
return 0;
gpiochip_remove:
gpiochip_remove(&ctrl->gc);
return err;
}
static int ath79_gpio_remove(struct platform_device *pdev)
{
struct ath79_gpio_ctrl *ctrl = platform_get_drvdata(pdev);
gpiochip_remove(&ctrl->gc);
return 0;
}
@ -319,7 +308,6 @@ static struct platform_driver ath79_gpio_driver = {
.of_match_table = ath79_gpio_of_match,
},
.probe = ath79_gpio_probe,
.remove = ath79_gpio_remove,
};
module_platform_driver(ath79_gpio_driver);

View File

@ -297,7 +297,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
static void gpio_irq_disable(struct irq_data *d)
{
struct davinci_gpio_regs __iomem *g = irq2regs(d);
u32 mask = (u32) irq_data_get_irq_handler_data(d);
uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d);
writel_relaxed(mask, &g->clr_falling);
writel_relaxed(mask, &g->clr_rising);
@ -306,7 +306,7 @@ static void gpio_irq_disable(struct irq_data *d)
static void gpio_irq_enable(struct irq_data *d)
{
struct davinci_gpio_regs __iomem *g = irq2regs(d);
u32 mask = (u32) irq_data_get_irq_handler_data(d);
uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d);
unsigned status = irqd_get_trigger_type(d);
status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
@ -447,7 +447,7 @@ davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq,
"davinci_gpio");
irq_set_irq_type(irq, IRQ_TYPE_NONE);
irq_set_chip_data(irq, (__force void *)g);
irq_set_handler_data(irq, (void *)__gpio_mask(hw));
irq_set_handler_data(irq, (void *)(uintptr_t)__gpio_mask(hw));
return 0;
}
@ -632,6 +632,7 @@ done:
static const struct of_device_id davinci_gpio_ids[] = {
{ .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip},
{ .compatible = "ti,am654-gpio", keystone_gpio_get_irq_chip},
{ .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip},
{ /* sentinel */ },
};

View File

@ -568,7 +568,6 @@ static int sprd_eic_probe(struct platform_device *pdev)
const struct sprd_eic_variant_data *pdata;
struct gpio_irq_chip *irq;
struct sprd_eic *sprd_eic;
struct resource *res;
int ret, i;
pdata = of_device_get_match_data(&pdev->dev);
@ -597,13 +596,9 @@ static int sprd_eic_probe(struct platform_device *pdev)
* have one bank EIC, thus base[1] and base[2] can be
* optional.
*/
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res)
continue;
sprd_eic->base[i] = devm_ioremap_resource(&pdev->dev, res);
sprd_eic->base[i] = devm_platform_ioremap_resource(pdev, i);
if (IS_ERR(sprd_eic->base[i]))
return PTR_ERR(sprd_eic->base[i]);
continue;
}
sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type];

View File

@ -270,10 +270,8 @@ static int em_gio_probe(struct platform_device *pdev)
int ret;
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p) {
ret = -ENOMEM;
goto err0;
}
if (!p)
return -ENOMEM;
p->pdev = pdev;
platform_set_drvdata(pdev, p);
@ -286,30 +284,22 @@ static int em_gio_probe(struct platform_device *pdev)
if (!io[0] || !io[1] || !irq[0] || !irq[1]) {
dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
ret = -EINVAL;
goto err0;
return -EINVAL;
}
p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start,
resource_size(io[0]));
if (!p->base0) {
dev_err(&pdev->dev, "failed to remap low I/O memory\n");
ret = -ENXIO;
goto err0;
}
if (!p->base0)
return -ENOMEM;
p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start,
resource_size(io[1]));
if (!p->base1) {
dev_err(&pdev->dev, "failed to remap high I/O memory\n");
ret = -ENXIO;
goto err0;
}
if (!p->base1)
return -ENOMEM;
if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
dev_err(&pdev->dev, "Missing ngpios OF property\n");
ret = -EINVAL;
goto err0;
return -EINVAL;
}
gpio_chip = &p->gpio_chip;
@ -339,9 +329,8 @@ static int em_gio_probe(struct platform_device *pdev)
p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0,
&em_gio_irq_domain_ops, p);
if (!p->irq_domain) {
ret = -ENXIO;
dev_err(&pdev->dev, "cannot initialize irq domain\n");
goto err0;
return -ENXIO;
}
if (devm_request_irq(&pdev->dev, irq[0]->start,
@ -358,7 +347,7 @@ static int em_gio_probe(struct platform_device *pdev)
goto err1;
}
ret = gpiochip_add_data(gpio_chip, p);
ret = devm_gpiochip_add_data(&pdev->dev, gpio_chip, p);
if (ret) {
dev_err(&pdev->dev, "failed to add GPIO controller\n");
goto err1;
@ -368,7 +357,6 @@ static int em_gio_probe(struct platform_device *pdev)
err1:
irq_domain_remove(p->irq_domain);
err0:
return ret;
}
@ -376,8 +364,6 @@ static int em_gio_remove(struct platform_device *pdev)
{
struct em_gio_priv *p = platform_get_drvdata(pdev);
gpiochip_remove(&p->gpio_chip);
irq_domain_remove(p->irq_domain);
return 0;
}

View File

@ -393,16 +393,13 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
static int ep93xx_gpio_probe(struct platform_device *pdev)
{
struct ep93xx_gpio *epg;
struct resource *res;
int i;
struct device *dev = &pdev->dev;
epg = devm_kzalloc(dev, sizeof(*epg), GFP_KERNEL);
epg = devm_kzalloc(&pdev->dev, sizeof(*epg), GFP_KERNEL);
if (!epg)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
epg->base = devm_ioremap_resource(dev, res);
epg->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(epg->base))
return PTR_ERR(epg->base);

View File

@ -226,6 +226,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ftgpio_gpio *g;
struct gpio_irq_chip *girq;
int irq;
int ret;
@ -277,6 +278,24 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
if (!IS_ERR(g->clk))
g->gc.set_config = ftgpio_gpio_set_config;
g->irq.name = "FTGPIO010";
g->irq.irq_ack = ftgpio_gpio_ack_irq;
g->irq.irq_mask = ftgpio_gpio_mask_irq;
g->irq.irq_unmask = ftgpio_gpio_unmask_irq;
g->irq.irq_set_type = ftgpio_gpio_set_irq_type;
girq = &g->gc.irq;
girq->chip = &g->irq;
girq->parent_handler = ftgpio_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
girq->parents[0] = irq;
ret = devm_gpiochip_add_data(dev, &g->gc, g);
if (ret)
goto dis_clk;
@ -289,22 +308,6 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
/* Clear any use of debounce */
writel(0x0, g->base + GPIO_DEBOUNCE_EN);
g->irq.name = "FTGPIO010";
g->irq.irq_ack = ftgpio_gpio_ack_irq;
g->irq.irq_mask = ftgpio_gpio_mask_irq;
g->irq.irq_unmask = ftgpio_gpio_unmask_irq;
g->irq.irq_set_type = ftgpio_gpio_set_irq_type;
ret = gpiochip_irqchip_add(&g->gc, &g->irq,
0, handle_bad_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_info(dev, "could not add irqchip\n");
goto dis_clk;
}
gpiochip_set_chained_irqchip(&g->gc, &g->irq,
irq, ftgpio_gpio_irq_handler);
platform_set_drvdata(pdev, g);
dev_info(dev, "FTGPIO010 @%p registered\n", g->base);

View File

@ -329,7 +329,6 @@ static int grgpio_probe(struct platform_device *ofdev)
void __iomem *regs;
struct gpio_chip *gc;
struct grgpio_priv *priv;
struct resource *res;
int err;
u32 prop;
s32 *irqmap;
@ -340,8 +339,7 @@ static int grgpio_probe(struct platform_device *ofdev)
if (!priv)
return -ENOMEM;
res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&ofdev->dev, res);
regs = devm_platform_ioremap_resource(ofdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);

View File

@ -205,20 +205,20 @@ static int ixp4xx_gpio_irq_domain_translate(struct irq_domain *domain,
unsigned long *hwirq,
unsigned int *type)
{
int ret;
/* We support standard DT translation */
if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
*hwirq = fwspec->param[0];
*type = fwspec->param[1];
return 0;
return irq_domain_translate_twocell(domain, fwspec,
hwirq, type);
}
/* This goes away when we transition to DT */
if (is_fwnode_irqchip(fwspec->fwnode)) {
if (fwspec->param_count != 2)
return -EINVAL;
*hwirq = fwspec->param[0];
*type = fwspec->param[1];
ret = irq_domain_translate_twocell(domain, fwspec,
hwirq, type);
if (ret)
return ret;
WARN_ON(*type == IRQ_TYPE_NONE);
return 0;
}

View File

@ -140,18 +140,17 @@ static void ttl_setup_device(struct ttl_module *mod)
static int ttl_probe(struct platform_device *pdev)
{
struct janz_platform_data *pdata;
struct device *dev = &pdev->dev;
struct ttl_module *mod;
struct gpio_chip *gpio;
int ret;
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(dev, "no platform data\n");
dev_err(&pdev->dev, "no platform data\n");
return -ENXIO;
}
mod = devm_kzalloc(dev, sizeof(*mod), GFP_KERNEL);
mod = devm_kzalloc(&pdev->dev, sizeof(*mod), GFP_KERNEL);
if (!mod)
return -ENOMEM;
@ -177,9 +176,9 @@ static int ttl_probe(struct platform_device *pdev)
gpio->base = -1;
gpio->ngpio = 20;
ret = devm_gpiochip_add_data(dev, gpio, NULL);
ret = devm_gpiochip_add_data(&pdev->dev, gpio, NULL);
if (ret) {
dev_err(dev, "unable to add GPIO chip\n");
dev_err(&pdev->dev, "unable to add GPIO chip\n");
return ret;
}

View File

@ -1,12 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO support for Cirrus Logic Madera codecs
*
* Copyright (C) 2015-2018 Cirrus Logic
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2.
*/
#include <linux/gpio/driver.h>

View File

@ -649,12 +649,12 @@ static int max732x_probe(struct i2c_client *client,
case 0x60:
chip->client_group_a = client;
if (nr_port > 8) {
c = i2c_new_dummy(client->adapter, addr_b);
if (!c) {
c = devm_i2c_new_dummy_device(&client->dev,
client->adapter, addr_b);
if (IS_ERR(c)) {
dev_err(&client->dev,
"Failed to allocate I2C device\n");
ret = -ENODEV;
goto out_failed;
return PTR_ERR(c);
}
chip->client_group_b = chip->client_dummy = c;
}
@ -662,12 +662,12 @@ static int max732x_probe(struct i2c_client *client,
case 0x50:
chip->client_group_b = client;
if (nr_port > 8) {
c = i2c_new_dummy(client->adapter, addr_a);
if (!c) {
c = devm_i2c_new_dummy_device(&client->dev,
client->adapter, addr_a);
if (IS_ERR(c)) {
dev_err(&client->dev,
"Failed to allocate I2C device\n");
ret = -ENODEV;
goto out_failed;
return PTR_ERR(c);
}
chip->client_group_a = chip->client_dummy = c;
}
@ -675,37 +675,33 @@ static int max732x_probe(struct i2c_client *client,
default:
dev_err(&client->dev, "invalid I2C address specified %02x\n",
client->addr);
ret = -EINVAL;
goto out_failed;
return -EINVAL;
}
if (nr_port > 8 && !chip->client_dummy) {
dev_err(&client->dev,
"Failed to allocate second group I2C device\n");
ret = -ENODEV;
goto out_failed;
return -ENODEV;
}
mutex_init(&chip->lock);
ret = max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]);
if (ret)
goto out_failed;
return ret;
if (nr_port > 8) {
ret = max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]);
if (ret)
goto out_failed;
return ret;
}
ret = gpiochip_add_data(&chip->gpio_chip, chip);
ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
if (ret)
goto out_failed;
return ret;
ret = max732x_irq_setup(chip, id);
if (ret) {
gpiochip_remove(&chip->gpio_chip);
goto out_failed;
}
if (ret)
return ret;
if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base,
@ -716,10 +712,6 @@ static int max732x_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip);
return 0;
out_failed:
i2c_unregister_device(chip->client_dummy);
return ret;
}
static int max732x_remove(struct i2c_client *client)
@ -739,11 +731,6 @@ static int max732x_remove(struct i2c_client *client)
}
}
gpiochip_remove(&chip->gpio_chip);
/* unregister any dummy i2c_client */
i2c_unregister_device(chip->client_dummy);
return 0;
}

View File

@ -315,7 +315,6 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
struct gpio_mockup_chip *chip)
{
struct gpio_mockup_dbgfs_private *priv;
struct dentry *evfile;
struct gpio_chip *gc;
const char *devname;
char *name;
@ -325,32 +324,25 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
devname = dev_name(&gc->gpiodev->dev);
chip->dbg_dir = debugfs_create_dir(devname, gpio_mockup_dbg_dir);
if (IS_ERR_OR_NULL(chip->dbg_dir))
goto err;
for (i = 0; i < gc->ngpio; i++) {
name = devm_kasprintf(dev, GFP_KERNEL, "%d", i);
if (!name)
goto err;
return;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
goto err;
return;
priv->chip = chip;
priv->offset = i;
priv->desc = &gc->gpiodev->descs[i];
evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv,
&gpio_mockup_debugfs_ops);
if (IS_ERR_OR_NULL(evfile))
goto err;
debugfs_create_file(name, 0200, chip->dbg_dir, priv,
&gpio_mockup_debugfs_ops);
}
return;
err:
dev_err(dev, "error creating debugfs files\n");
}
static int gpio_mockup_name_lines(struct device *dev,
@ -447,8 +439,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
if (rv)
return rv;
if (!IS_ERR_OR_NULL(gpio_mockup_dbg_dir))
gpio_mockup_debugfs_setup(dev, chip);
gpio_mockup_debugfs_setup(dev, chip);
return 0;
}
@ -501,8 +492,6 @@ static int __init gpio_mockup_init(void)
}
gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup", NULL);
if (IS_ERR_OR_NULL(gpio_mockup_dbg_dir))
gpio_mockup_err("error creating debugfs directory\n");
err = platform_driver_register(&gpio_mockup_driver);
if (err) {

View File

@ -38,6 +38,7 @@
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
@ -618,18 +619,14 @@ static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
ret = -EBUSY;
} else {
desc = gpiochip_request_own_desc(&mvchip->chip,
pwm->hwpwm, "mvebu-pwm", 0);
pwm->hwpwm, "mvebu-pwm",
GPIO_ACTIVE_HIGH,
GPIOD_OUT_LOW);
if (IS_ERR(desc)) {
ret = PTR_ERR(desc);
goto out;
}
ret = gpiod_direction_output(desc, 0);
if (ret) {
gpiochip_free_own_desc(desc);
goto out;
}
mvpwm->gpiod = desc;
}
out:

View File

@ -44,8 +44,9 @@ struct gpio_regs {
};
struct gpio_bank {
struct list_head node;
void __iomem *base;
const struct omap_gpio_reg_offs *regs;
int irq;
u32 non_wakeup_gpios;
u32 enabled_non_wakeup_gpios;
@ -72,11 +73,7 @@ struct gpio_bank {
int context_loss_count;
void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
void (*set_dataout_multiple)(struct gpio_bank *bank,
unsigned long *mask, unsigned long *bits);
int (*get_context_loss_count)(struct device *dev);
struct omap_gpio_reg_offs *regs;
};
#define GPIO_MOD_CTRL_BIT BIT(0)
@ -92,20 +89,25 @@ static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d)
return gpiochip_get_data(chip);
}
static inline u32 omap_gpio_rmw(void __iomem *reg, u32 mask, bool set)
{
u32 val = readl_relaxed(reg);
if (set)
val |= mask;
else
val &= ~mask;
writel_relaxed(val, reg);
return val;
}
static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
int is_input)
{
void __iomem *reg = bank->base;
u32 l;
reg += bank->regs->direction;
l = readl_relaxed(reg);
if (is_input)
l |= BIT(gpio);
else
l &= ~(BIT(gpio));
writel_relaxed(l, reg);
bank->context.oe = l;
bank->context.oe = omap_gpio_rmw(bank->base + bank->regs->direction,
BIT(gpio), is_input);
}
@ -131,88 +133,8 @@ static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, unsigned offset,
static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, unsigned offset,
int enable)
{
void __iomem *reg = bank->base + bank->regs->dataout;
u32 gpio_bit = BIT(offset);
u32 l;
l = readl_relaxed(reg);
if (enable)
l |= gpio_bit;
else
l &= ~gpio_bit;
writel_relaxed(l, reg);
bank->context.dataout = l;
}
static int omap_get_gpio_datain(struct gpio_bank *bank, int offset)
{
void __iomem *reg = bank->base + bank->regs->datain;
return (readl_relaxed(reg) & (BIT(offset))) != 0;
}
static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset)
{
void __iomem *reg = bank->base + bank->regs->dataout;
return (readl_relaxed(reg) & (BIT(offset))) != 0;
}
/* set multiple data out values using dedicate set/clear register */
static void omap_set_gpio_dataout_reg_multiple(struct gpio_bank *bank,
unsigned long *mask,
unsigned long *bits)
{
void __iomem *reg = bank->base;
u32 l;
l = *bits & *mask;
writel_relaxed(l, reg + bank->regs->set_dataout);
bank->context.dataout |= l;
l = ~*bits & *mask;
writel_relaxed(l, reg + bank->regs->clr_dataout);
bank->context.dataout &= ~l;
}
/* set multiple data out values using mask register */
static void omap_set_gpio_dataout_mask_multiple(struct gpio_bank *bank,
unsigned long *mask,
unsigned long *bits)
{
void __iomem *reg = bank->base + bank->regs->dataout;
u32 l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask);
writel_relaxed(l, reg);
bank->context.dataout = l;
}
static unsigned long omap_get_gpio_datain_multiple(struct gpio_bank *bank,
unsigned long *mask)
{
void __iomem *reg = bank->base + bank->regs->datain;
return readl_relaxed(reg) & *mask;
}
static unsigned long omap_get_gpio_dataout_multiple(struct gpio_bank *bank,
unsigned long *mask)
{
void __iomem *reg = bank->base + bank->regs->dataout;
return readl_relaxed(reg) & *mask;
}
static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
{
int l = readl_relaxed(base + reg);
if (set)
l |= mask;
else
l &= ~mask;
writel_relaxed(l, base + reg);
bank->context.dataout = omap_gpio_rmw(bank->base + bank->regs->dataout,
BIT(offset), enable);
}
static inline void omap_gpio_dbck_enable(struct gpio_bank *bank)
@ -256,7 +178,6 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
unsigned debounce)
{
void __iomem *reg;
u32 val;
u32 l;
bool enable = !!debounce;
@ -273,19 +194,11 @@ static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
l = BIT(offset);
clk_enable(bank->dbck);
reg = bank->base + bank->regs->debounce;
writel_relaxed(debounce, reg);
writel_relaxed(debounce, bank->base + bank->regs->debounce);
reg = bank->base + bank->regs->debounce_en;
val = readl_relaxed(reg);
if (enable)
val |= l;
else
val &= ~l;
val = omap_gpio_rmw(bank->base + bank->regs->debounce_en, l, enable);
bank->dbck_enable_mask = val;
writel_relaxed(val, reg);
clk_disable(bank->dbck);
/*
* Enable debounce clock per module.
@ -360,9 +273,9 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
void __iomem *base = bank->base;
u32 gpio_bit = BIT(gpio);
omap_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit,
omap_gpio_rmw(base + bank->regs->leveldetect0, gpio_bit,
trigger & IRQ_TYPE_LEVEL_LOW);
omap_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
omap_gpio_rmw(base + bank->regs->leveldetect1, gpio_bit,
trigger & IRQ_TYPE_LEVEL_HIGH);
/*
@ -370,9 +283,9 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
* to be woken from idle state. Set the appropriate edge detection
* in addition to the level detection.
*/
omap_gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
omap_gpio_rmw(base + bank->regs->risingdetect, gpio_bit,
trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH));
omap_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
omap_gpio_rmw(base + bank->regs->fallingdetect, gpio_bit,
trigger & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW));
bank->context.leveldetect0 =
@ -384,11 +297,8 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
bank->context.fallingdetect =
readl_relaxed(bank->base + bank->regs->fallingdetect);
if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
bank->context.wake_en =
readl_relaxed(bank->base + bank->regs->wkup_en);
}
bank->level_mask = bank->context.leveldetect0 |
bank->context.leveldetect1;
/* This part needs to be executed always for OMAP{34xx, 44xx} */
if (!bank->regs->irqctrl && !omap_gpio_is_off_wakeup_capable(bank, gpio)) {
@ -403,44 +313,25 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
else
bank->enabled_non_wakeup_gpios &= ~gpio_bit;
}
bank->level_mask =
readl_relaxed(bank->base + bank->regs->leveldetect0) |
readl_relaxed(bank->base + bank->regs->leveldetect1);
}
#ifdef CONFIG_ARCH_OMAP1
/*
* This only applies to chips that can't do both rising and falling edge
* detection at once. For all other chips, this function is a noop.
*/
static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
{
void __iomem *reg = bank->base;
u32 l = 0;
if (IS_ENABLED(CONFIG_ARCH_OMAP1) && bank->regs->irqctrl) {
void __iomem *reg = bank->base + bank->regs->irqctrl;
if (!bank->regs->irqctrl)
return;
reg += bank->regs->irqctrl;
l = readl_relaxed(reg);
if ((l >> gpio) & 1)
l &= ~(BIT(gpio));
else
l |= BIT(gpio);
writel_relaxed(l, reg);
writel_relaxed(readl_relaxed(reg) ^ BIT(gpio), reg);
}
}
#else
static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
#endif
static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio,
unsigned trigger)
{
void __iomem *reg = bank->base;
void __iomem *base = bank->base;
u32 l = 0;
if (bank->regs->leveldetect0 && bank->regs->wkup_en) {
@ -472,11 +363,6 @@ static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio,
l |= 2 << (gpio << 1);
if (trigger & IRQ_TYPE_EDGE_FALLING)
l |= BIT(gpio << 1);
/* Enable wake-up during idle for dynamic tick */
omap_gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger);
bank->context.wake_en =
readl_relaxed(bank->base + bank->regs->wkup_en);
writel_relaxed(l, reg);
}
return 0;
@ -505,17 +391,6 @@ static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned offset)
static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset)
{
void __iomem *base = bank->base;
if (bank->regs->wkup_en &&
!LINE_USED(bank->mod_usage, offset) &&
!LINE_USED(bank->irq_usage, offset)) {
/* Disable wake-up during idle for dynamic tick */
omap_gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0);
bank->context.wake_en =
readl_relaxed(bank->base + bank->regs->wkup_en);
}
if (bank->regs->ctrl && !BANK_USED(bank)) {
void __iomem *reg = bank->base + bank->regs->ctrl;
u32 ctrl;
@ -626,57 +501,39 @@ static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank)
return l;
}
static void omap_enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
{
void __iomem *reg = bank->base;
u32 l;
if (bank->regs->set_irqenable) {
reg += bank->regs->set_irqenable;
l = gpio_mask;
bank->context.irqenable1 |= gpio_mask;
} else {
reg += bank->regs->irqenable;
l = readl_relaxed(reg);
if (bank->regs->irqenable_inv)
l &= ~gpio_mask;
else
l |= gpio_mask;
bank->context.irqenable1 = l;
}
writel_relaxed(l, reg);
}
static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
{
void __iomem *reg = bank->base;
u32 l;
if (bank->regs->clr_irqenable) {
reg += bank->regs->clr_irqenable;
l = gpio_mask;
bank->context.irqenable1 &= ~gpio_mask;
} else {
reg += bank->regs->irqenable;
l = readl_relaxed(reg);
if (bank->regs->irqenable_inv)
l |= gpio_mask;
else
l &= ~gpio_mask;
bank->context.irqenable1 = l;
}
writel_relaxed(l, reg);
}
static inline void omap_set_gpio_irqenable(struct gpio_bank *bank,
unsigned offset, int enable)
{
if (enable)
omap_enable_gpio_irqbank(bank, BIT(offset));
else
omap_disable_gpio_irqbank(bank, BIT(offset));
void __iomem *reg = bank->base;
u32 gpio_mask = BIT(offset);
if (bank->regs->set_irqenable && bank->regs->clr_irqenable) {
if (enable) {
reg += bank->regs->set_irqenable;
bank->context.irqenable1 |= gpio_mask;
} else {
reg += bank->regs->clr_irqenable;
bank->context.irqenable1 &= ~gpio_mask;
}
writel_relaxed(gpio_mask, reg);
} else {
bank->context.irqenable1 =
omap_gpio_rmw(reg + bank->regs->irqenable, gpio_mask,
enable ^ bank->regs->irqenable_inv);
}
/*
* Program GPIO wakeup along with IRQ enable to satisfy OMAP4430 TRM
* note requiring correlation between the IRQ enable registers and
* the wakeup registers. In any case, we want wakeup from idle
* enabled for the GPIOs which support this feature.
*/
if (bank->regs->wkup_en &&
(bank->regs->edgectrl1 || !(bank->non_wakeup_gpios & gpio_mask))) {
bank->context.wake_en =
omap_gpio_rmw(bank->base + bank->regs->wkup_en,
gpio_mask, enable);
}
}
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
@ -687,38 +544,6 @@ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
return irq_set_irq_wake(bank->irq, enable);
}
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank = gpiochip_get_data(chip);
unsigned long flags;
pm_runtime_get_sync(chip->parent);
raw_spin_lock_irqsave(&bank->lock, flags);
omap_enable_gpio_module(bank, offset);
bank->mod_usage |= BIT(offset);
raw_spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank = gpiochip_get_data(chip);
unsigned long flags;
raw_spin_lock_irqsave(&bank->lock, flags);
bank->mod_usage &= ~(BIT(offset));
if (!LINE_USED(bank->irq_usage, offset)) {
omap_set_gpio_direction(bank, offset, 1);
omap_clear_gpio_debounce(bank, offset);
}
omap_disable_gpio_module(bank, offset);
raw_spin_unlock_irqrestore(&bank->lock, flags);
pm_runtime_put(chip->parent);
}
/*
* We need to unmask the GPIO bank interrupt as soon as possible to
* avoid missing GPIO interrupts for other lines in the bank.
@ -731,7 +556,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
{
void __iomem *isr_reg = NULL;
u32 enabled, isr, level_mask;
u32 enabled, isr, edge;
unsigned int bit;
struct gpio_bank *bank = gpiobank;
unsigned long wa_lock_flags;
@ -751,16 +576,14 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
enabled = omap_get_gpio_irqbank_mask(bank);
isr = readl_relaxed(isr_reg) & enabled;
if (bank->level_mask)
level_mask = bank->level_mask & enabled;
else
level_mask = 0;
/* clear edge sensitive interrupts before handler(s) are
called so that we don't miss any interrupt occurred while
executing them */
if (isr & ~level_mask)
omap_clear_gpio_irqbank(bank, isr & ~level_mask);
/*
* Clear edge sensitive interrupts before calling handler(s)
* so subsequent edge transitions are not missed while the
* handlers are running.
*/
edge = isr & ~bank->level_mask;
if (edge)
omap_clear_gpio_irqbank(bank, edge);
raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
@ -807,8 +630,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
if (!LINE_USED(bank->mod_usage, offset))
omap_set_gpio_direction(bank, offset, 1);
else if (!omap_gpio_is_input(bank, offset))
goto err;
omap_enable_gpio_module(bank, offset);
bank->irq_usage |= BIT(offset);
@ -816,9 +637,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
omap_gpio_unmask_irq(d);
return 0;
err:
raw_spin_unlock_irqrestore(&bank->lock, flags);
return -EINVAL;
}
static void omap_gpio_irq_shutdown(struct irq_data *d)
@ -829,9 +647,9 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
raw_spin_lock_irqsave(&bank->lock, flags);
bank->irq_usage &= ~(BIT(offset));
omap_set_gpio_irqenable(bank, offset, 0);
omap_clear_gpio_irqstatus(bank, offset);
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
omap_clear_gpio_irqstatus(bank, offset);
omap_set_gpio_irqenable(bank, offset, 0);
if (!LINE_USED(bank->mod_usage, offset))
omap_clear_gpio_debounce(bank, offset);
omap_disable_gpio_module(bank, offset);
@ -852,14 +670,6 @@ static void gpio_irq_bus_sync_unlock(struct irq_data *data)
pm_runtime_put(bank->chip.parent);
}
static void omap_gpio_ack_irq(struct irq_data *d)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
unsigned offset = d->hwirq;
omap_clear_gpio_irqstatus(bank, offset);
}
static void omap_gpio_mask_irq(struct irq_data *d)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
@ -867,8 +677,8 @@ static void omap_gpio_mask_irq(struct irq_data *d)
unsigned long flags;
raw_spin_lock_irqsave(&bank->lock, flags);
omap_set_gpio_irqenable(bank, offset, 0);
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
omap_set_gpio_irqenable(bank, offset, 0);
raw_spin_unlock_irqrestore(&bank->lock, flags);
}
@ -880,9 +690,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
unsigned long flags;
raw_spin_lock_irqsave(&bank->lock, flags);
if (trigger)
omap_set_gpio_triggering(bank, offset, trigger);
omap_set_gpio_irqenable(bank, offset, 1);
/*
@ -890,9 +697,13 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
* is cleared, thus after the handler has run. OMAP4 needs this done
* after enabing the interrupt to clear the wakeup status.
*/
if (bank->level_mask & BIT(offset))
if (bank->regs->leveldetect0 && bank->regs->wkup_en &&
trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
omap_clear_gpio_irqstatus(bank, offset);
if (trigger)
omap_set_gpio_triggering(bank, offset, trigger);
raw_spin_unlock_irqrestore(&bank->lock, flags);
}
@ -958,19 +769,44 @@ static inline void omap_mpuio_init(struct gpio_bank *bank)
/*---------------------------------------------------------------------*/
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank = gpiochip_get_data(chip);
unsigned long flags;
pm_runtime_get_sync(chip->parent);
raw_spin_lock_irqsave(&bank->lock, flags);
omap_enable_gpio_module(bank, offset);
bank->mod_usage |= BIT(offset);
raw_spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank = gpiochip_get_data(chip);
unsigned long flags;
raw_spin_lock_irqsave(&bank->lock, flags);
bank->mod_usage &= ~(BIT(offset));
if (!LINE_USED(bank->irq_usage, offset)) {
omap_set_gpio_direction(bank, offset, 1);
omap_clear_gpio_debounce(bank, offset);
}
omap_disable_gpio_module(bank, offset);
raw_spin_unlock_irqrestore(&bank->lock, flags);
pm_runtime_put(chip->parent);
}
static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank;
unsigned long flags;
void __iomem *reg;
int dir;
struct gpio_bank *bank = gpiochip_get_data(chip);
bank = gpiochip_get_data(chip);
reg = bank->base + bank->regs->direction;
raw_spin_lock_irqsave(&bank->lock, flags);
dir = !!(readl_relaxed(reg) & BIT(offset));
raw_spin_unlock_irqrestore(&bank->lock, flags);
return dir;
return !!(readl_relaxed(bank->base + bank->regs->direction) &
BIT(offset));
}
static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
@ -987,14 +823,15 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
static int omap_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank;
bank = gpiochip_get_data(chip);
struct gpio_bank *bank = gpiochip_get_data(chip);
void __iomem *reg;
if (omap_gpio_is_input(bank, offset))
return omap_get_gpio_datain(bank, offset);
reg = bank->base + bank->regs->datain;
else
return omap_get_gpio_dataout(bank, offset);
reg = bank->base + bank->regs->dataout;
return (readl_relaxed(reg) & BIT(offset)) != 0;
}
static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value)
@ -1014,18 +851,20 @@ static int omap_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct gpio_bank *bank = gpiochip_get_data(chip);
void __iomem *reg = bank->base + bank->regs->direction;
unsigned long in = readl_relaxed(reg), l;
void __iomem *base = bank->base;
u32 direction, m, val = 0;
*bits = 0;
direction = readl_relaxed(base + bank->regs->direction);
l = in & *mask;
if (l)
*bits |= omap_get_gpio_datain_multiple(bank, &l);
m = direction & *mask;
if (m)
val |= readl_relaxed(base + bank->regs->datain) & m;
l = ~in & *mask;
if (l)
*bits |= omap_get_gpio_dataout_multiple(bank, &l);
m = ~direction & *mask;
if (m)
val |= readl_relaxed(base + bank->regs->dataout) & m;
*bits = val;
return 0;
}
@ -1078,10 +917,14 @@ static void omap_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct gpio_bank *bank = gpiochip_get_data(chip);
void __iomem *reg = bank->base + bank->regs->dataout;
unsigned long flags;
u32 l;
raw_spin_lock_irqsave(&bank->lock, flags);
bank->set_dataout_multiple(bank, mask, bits);
l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask);
writel_relaxed(l, reg);
bank->context.dataout = l;
raw_spin_unlock_irqrestore(&bank->lock, flags);
}
@ -1115,9 +958,9 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
return;
}
omap_gpio_rmw(base, bank->regs->irqenable, l,
omap_gpio_rmw(base + bank->regs->irqenable, l,
bank->regs->irqenable_inv);
omap_gpio_rmw(base, bank->regs->irqstatus, l,
omap_gpio_rmw(base + bank->regs->irqstatus, l,
!bank->regs->irqenable_inv);
if (bank->regs->debounce_en)
writel_relaxed(0, base + bank->regs->debounce_en);
@ -1180,11 +1023,8 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
#endif
/* MPUIO is a bit different, reading IRQ status clears it */
if (bank->is_mpuio) {
irqc->irq_ack = dummy_irq_chip.irq_ack;
if (!bank->regs->wkup_en)
irqc->irq_set_wake = NULL;
}
if (bank->is_mpuio && !bank->regs->wkup_en)
irqc->irq_set_wake = NULL;
irq = &bank->chip.irq;
irq->chip = irqc;
@ -1215,7 +1055,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
static void omap_gpio_init_context(struct gpio_bank *p)
{
struct omap_gpio_reg_offs *regs = p->regs;
const struct omap_gpio_reg_offs *regs = p->regs;
void __iomem *base = p->base;
p->context.ctrl = readl_relaxed(base + regs->ctrl);
@ -1227,60 +1067,56 @@ static void omap_gpio_init_context(struct gpio_bank *p)
p->context.fallingdetect = readl_relaxed(base + regs->fallingdetect);
p->context.irqenable1 = readl_relaxed(base + regs->irqenable);
p->context.irqenable2 = readl_relaxed(base + regs->irqenable2);
if (regs->set_dataout && p->regs->clr_dataout)
p->context.dataout = readl_relaxed(base + regs->set_dataout);
else
p->context.dataout = readl_relaxed(base + regs->dataout);
p->context.dataout = readl_relaxed(base + regs->dataout);
p->context_valid = true;
}
static void omap_gpio_restore_context(struct gpio_bank *bank)
{
writel_relaxed(bank->context.wake_en,
bank->base + bank->regs->wkup_en);
writel_relaxed(bank->context.ctrl, bank->base + bank->regs->ctrl);
writel_relaxed(bank->context.leveldetect0,
bank->base + bank->regs->leveldetect0);
writel_relaxed(bank->context.leveldetect1,
bank->base + bank->regs->leveldetect1);
writel_relaxed(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
writel_relaxed(bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect);
if (bank->regs->set_dataout && bank->regs->clr_dataout)
writel_relaxed(bank->context.dataout,
bank->base + bank->regs->set_dataout);
else
writel_relaxed(bank->context.dataout,
bank->base + bank->regs->dataout);
writel_relaxed(bank->context.oe, bank->base + bank->regs->direction);
const struct omap_gpio_reg_offs *regs = bank->regs;
void __iomem *base = bank->base;
writel_relaxed(bank->context.wake_en, base + regs->wkup_en);
writel_relaxed(bank->context.ctrl, base + regs->ctrl);
writel_relaxed(bank->context.leveldetect0, base + regs->leveldetect0);
writel_relaxed(bank->context.leveldetect1, base + regs->leveldetect1);
writel_relaxed(bank->context.risingdetect, base + regs->risingdetect);
writel_relaxed(bank->context.fallingdetect, base + regs->fallingdetect);
writel_relaxed(bank->context.dataout, base + regs->dataout);
writel_relaxed(bank->context.oe, base + regs->direction);
if (bank->dbck_enable_mask) {
writel_relaxed(bank->context.debounce, bank->base +
bank->regs->debounce);
writel_relaxed(bank->context.debounce, base + regs->debounce);
writel_relaxed(bank->context.debounce_en,
bank->base + bank->regs->debounce_en);
base + regs->debounce_en);
}
writel_relaxed(bank->context.irqenable1,
bank->base + bank->regs->irqenable);
writel_relaxed(bank->context.irqenable2,
bank->base + bank->regs->irqenable2);
writel_relaxed(bank->context.irqenable1, base + regs->irqenable);
writel_relaxed(bank->context.irqenable2, base + regs->irqenable2);
}
static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
{
struct device *dev = bank->chip.parent;
void __iomem *base = bank->base;
u32 nowake;
u32 mask, nowake;
bank->saved_datain = readl_relaxed(base + bank->regs->datain);
if (!bank->enabled_non_wakeup_gpios)
goto update_gpio_context_count;
/* Check for pending EDGE_FALLING, ignore EDGE_BOTH */
mask = bank->enabled_non_wakeup_gpios & bank->context.fallingdetect;
mask &= ~bank->context.risingdetect;
bank->saved_datain |= mask;
/* Check for pending EDGE_RISING, ignore EDGE_BOTH */
mask = bank->enabled_non_wakeup_gpios & bank->context.risingdetect;
mask &= ~bank->context.fallingdetect;
bank->saved_datain &= ~mask;
if (!may_lose_context)
goto update_gpio_context_count;
@ -1291,8 +1127,8 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
*/
if (!bank->loses_context && bank->enabled_non_wakeup_gpios) {
nowake = bank->enabled_non_wakeup_gpios;
omap_gpio_rmw(base, bank->regs->fallingdetect, nowake, ~nowake);
omap_gpio_rmw(base, bank->regs->risingdetect, nowake, ~nowake);
omap_gpio_rmw(base + bank->regs->fallingdetect, nowake, ~nowake);
omap_gpio_rmw(base + bank->regs->risingdetect, nowake, ~nowake);
}
update_gpio_context_count:
@ -1421,7 +1257,7 @@ static int gpio_omap_cpu_notifier(struct notifier_block *nb,
return NOTIFY_OK;
}
static struct omap_gpio_reg_offs omap2_gpio_regs = {
static const struct omap_gpio_reg_offs omap2_gpio_regs = {
.revision = OMAP24XX_GPIO_REVISION,
.direction = OMAP24XX_GPIO_OE,
.datain = OMAP24XX_GPIO_DATAIN,
@ -1444,7 +1280,7 @@ static struct omap_gpio_reg_offs omap2_gpio_regs = {
.fallingdetect = OMAP24XX_GPIO_FALLINGDETECT,
};
static struct omap_gpio_reg_offs omap4_gpio_regs = {
static const struct omap_gpio_reg_offs omap4_gpio_regs = {
.revision = OMAP4_GPIO_REVISION,
.direction = OMAP4_GPIO_OE,
.datain = OMAP4_GPIO_DATAIN,
@ -1453,6 +1289,8 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
.clr_dataout = OMAP4_GPIO_CLEARDATAOUT,
.irqstatus = OMAP4_GPIO_IRQSTATUS0,
.irqstatus2 = OMAP4_GPIO_IRQSTATUS1,
.irqstatus_raw0 = OMAP4_GPIO_IRQSTATUSRAW0,
.irqstatus_raw1 = OMAP4_GPIO_IRQSTATUSRAW1,
.irqenable = OMAP4_GPIO_IRQSTATUSSET0,
.irqenable2 = OMAP4_GPIO_IRQSTATUSSET1,
.set_irqenable = OMAP4_GPIO_IRQSTATUSSET0,
@ -1528,7 +1366,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
irqc->irq_startup = omap_gpio_irq_startup,
irqc->irq_shutdown = omap_gpio_irq_shutdown,
irqc->irq_ack = omap_gpio_ack_irq,
irqc->irq_ack = dummy_irq_chip.irq_ack,
irqc->irq_mask = omap_gpio_mask_irq,
irqc->irq_unmask = omap_gpio_unmask_irq,
irqc->irq_set_type = omap_gpio_irq_type,
@ -1572,14 +1410,10 @@ static int omap_gpio_probe(struct platform_device *pdev)
pdata->get_context_loss_count;
}
if (bank->regs->set_dataout && bank->regs->clr_dataout) {
if (bank->regs->set_dataout && bank->regs->clr_dataout)
bank->set_dataout = omap_set_gpio_dataout_reg;
bank->set_dataout_multiple = omap_set_gpio_dataout_reg_multiple;
} else {
else
bank->set_dataout = omap_set_gpio_dataout_mask;
bank->set_dataout_multiple =
omap_set_gpio_dataout_mask_multiple;
}
raw_spin_lock_init(&bank->lock);
raw_spin_lock_init(&bank->wa_lock);
@ -1635,7 +1469,6 @@ static int omap_gpio_remove(struct platform_device *pdev)
struct gpio_bank *bank = platform_get_drvdata(pdev);
cpu_pm_unregister_notifier(&bank->nb);
list_del(&bank->node);
gpiochip_remove(&bank->chip);
pm_runtime_disable(&pdev->dev);
if (bank->dbck_flag)

View File

@ -1178,6 +1178,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
{ .compatible = "ti,tca9539", .data = OF_953X(16, PCA_INT), },
{ .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), },

View File

@ -283,6 +283,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
struct pl061 *pl061;
struct gpio_irq_chip *girq;
int ret, irq;
pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL);
@ -310,10 +311,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
pl061->gc.parent = dev;
pl061->gc.owner = THIS_MODULE;
ret = gpiochip_add_data(&pl061->gc, pl061);
if (ret)
return ret;
/*
* irq_chip support
*/
@ -332,19 +329,24 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
}
pl061->parent_irq = irq;
ret = gpiochip_irqchip_add(&pl061->gc, &pl061->irq_chip,
0, handle_bad_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_info(&adev->dev, "could not add irqchip\n");
girq = &pl061->gc.irq;
girq->chip = &pl061->irq_chip;
girq->parent_handler = pl061_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
girq->parents[0] = irq;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
ret = devm_gpiochip_add_data(dev, &pl061->gc, pl061);
if (ret)
return ret;
}
gpiochip_set_chained_irqchip(&pl061->gc, &pl061->irq_chip,
irq, pl061_irq_handler);
amba_set_drvdata(adev, pl061);
dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n",
&adev->res.start);
dev_info(dev, "PL061 GPIO chip registered\n");
return 0;
}

View File

@ -489,7 +489,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
irq_chip->irq_unmask = gpio_rcar_irq_enable;
irq_chip->irq_set_type = gpio_rcar_irq_set_type;
irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
ret = gpiochip_add_data(gpio_chip, p);
if (ret) {

View File

@ -211,20 +211,22 @@ static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
static int gpio_siox_probe(struct siox_device *sdevice)
{
struct gpio_siox_ddata *ddata;
struct gpio_irq_chip *girq;
struct device *dev = &sdevice->dev;
int ret;
ddata = devm_kzalloc(&sdevice->dev, sizeof(*ddata), GFP_KERNEL);
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
dev_set_drvdata(&sdevice->dev, ddata);
dev_set_drvdata(dev, ddata);
mutex_init(&ddata->lock);
spin_lock_init(&ddata->irqlock);
ddata->gchip.base = -1;
ddata->gchip.can_sleep = 1;
ddata->gchip.parent = &sdevice->dev;
ddata->gchip.parent = dev;
ddata->gchip.owner = THIS_MODULE;
ddata->gchip.get = gpio_siox_get;
ddata->gchip.set = gpio_siox_set;
@ -239,54 +241,27 @@ static int gpio_siox_probe(struct siox_device *sdevice)
ddata->ichip.irq_unmask = gpio_siox_irq_unmask;
ddata->ichip.irq_set_type = gpio_siox_irq_set_type;
ret = gpiochip_add(&ddata->gchip);
if (ret) {
dev_err(&sdevice->dev,
"Failed to register gpio chip (%d)\n", ret);
goto err_gpiochip;
}
girq = &ddata->gchip.irq;
girq->chip = &ddata->ichip;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
ret = gpiochip_irqchip_add(&ddata->gchip, &ddata->ichip,
0, handle_level_irq, IRQ_TYPE_EDGE_RISING);
if (ret) {
dev_err(&sdevice->dev,
"Failed to register irq chip (%d)\n", ret);
err_gpiochip:
gpiochip_remove(&ddata->gchip);
}
ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL);
if (ret)
dev_err(dev, "Failed to register gpio chip (%d)\n", ret);
return ret;
}
static int gpio_siox_remove(struct siox_device *sdevice)
{
struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
gpiochip_remove(&ddata->gchip);
return 0;
}
static struct siox_driver gpio_siox_driver = {
.probe = gpio_siox_probe,
.remove = gpio_siox_remove,
.set_data = gpio_siox_set_data,
.get_data = gpio_siox_get_data,
.driver = {
.name = "gpio-siox",
},
};
static int __init gpio_siox_init(void)
{
return siox_driver_register(&gpio_siox_driver);
}
module_init(gpio_siox_init);
static void __exit gpio_siox_exit(void)
{
siox_driver_unregister(&gpio_siox_driver);
}
module_exit(gpio_siox_exit);
module_siox_driver(gpio_siox_driver);
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("SIOX gpio driver");

View File

@ -15,8 +15,6 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <lantiq_soc.h>
/*
* The Serial To Parallel (STP) is found on MIPS based Lantiq socs. It is a
* peripheral controller used to drive external shift register cascades. At most
@ -71,8 +69,7 @@
#define xway_stp_r32(m, reg) __raw_readl(m + reg)
#define xway_stp_w32(m, val, reg) __raw_writel(val, m + reg)
#define xway_stp_w32_mask(m, clear, set, reg) \
ltq_w32((ltq_r32(m + reg) & ~(clear)) | (set), \
m + reg)
xway_stp_w32(m, (xway_stp_r32(m, reg) & ~(clear)) | (set), reg)
struct xway_stp {
struct gpio_chip gc;
@ -156,9 +153,9 @@ static int xway_stp_request(struct gpio_chip *gc, unsigned gpio)
/**
* xway_stp_hw_init() - Configure the STP unit and enable the clock gate
* @virt: pointer to the remapped register range
* @chip: Pointer to the xway_stp chip structure
*/
static int xway_stp_hw_init(struct xway_stp *chip)
static void xway_stp_hw_init(struct xway_stp *chip)
{
/* sane defaults */
xway_stp_w32(chip->virt, 0, XWAY_STP_AR);
@ -201,8 +198,6 @@ static int xway_stp_hw_init(struct xway_stp *chip)
if (chip->reserved)
xway_stp_w32_mask(chip->virt, XWAY_STP_UPD_MASK,
XWAY_STP_UPD_FPI, XWAY_STP_CON1);
return 0;
}
static int xway_stp_probe(struct platform_device *pdev)
@ -258,21 +253,27 @@ static int xway_stp_probe(struct platform_device *pdev)
if (!of_find_property(pdev->dev.of_node, "lantiq,rising", NULL))
chip->edge = XWAY_STP_FALLING;
clk = clk_get(&pdev->dev, NULL);
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "Failed to get clock\n");
return PTR_ERR(clk);
}
clk_enable(clk);
ret = xway_stp_hw_init(chip);
if (!ret)
ret = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
ret = clk_prepare_enable(clk);
if (ret)
return ret;
if (!ret)
dev_info(&pdev->dev, "Init done\n");
xway_stp_hw_init(chip);
return ret;
ret = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
if (ret) {
clk_disable_unprepare(clk);
return ret;
}
dev_info(&pdev->dev, "Init done\n");
return 0;
}
static const struct of_device_id xway_stp_match[] = {

View File

@ -541,8 +541,8 @@ DEFINE_SHOW_ATTRIBUTE(tegra_dbg_gpio);
static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
{
(void) debugfs_create_file("tegra_gpio", 0444,
NULL, tgi, &tegra_dbg_gpio_fops);
debugfs_create_file("tegra_gpio", 0444, NULL, tgi,
&tegra_dbg_gpio_fops);
}
#else

View File

@ -265,7 +265,8 @@ static int vf610_gpio_probe(struct platform_device *pdev)
return port->irq;
port->clk_port = devm_clk_get(dev, "port");
if (!IS_ERR(port->clk_port)) {
ret = PTR_ERR_OR_ZERO(port->clk_port);
if (!ret) {
ret = clk_prepare_enable(port->clk_port);
if (ret)
return ret;
@ -273,16 +274,17 @@ static int vf610_gpio_probe(struct platform_device *pdev)
port->clk_port);
if (ret)
return ret;
} else if (port->clk_port == ERR_PTR(-EPROBE_DEFER)) {
} else if (ret == -EPROBE_DEFER) {
/*
* Percolate deferrals, for anything else,
* just live without the clocking.
*/
return PTR_ERR(port->clk_port);
return ret;
}
port->clk_gpio = devm_clk_get(dev, "gpio");
if (!IS_ERR(port->clk_gpio)) {
ret = PTR_ERR_OR_ZERO(port->clk_gpio);
if (!ret) {
ret = clk_prepare_enable(port->clk_gpio);
if (ret)
return ret;
@ -290,8 +292,8 @@ static int vf610_gpio_probe(struct platform_device *pdev)
port->clk_gpio);
if (ret)
return ret;
} else if (port->clk_gpio == ERR_PTR(-EPROBE_DEFER)) {
return PTR_ERR(port->clk_gpio);
} else if (ret == -EPROBE_DEFER) {
return ret;
}
gc = &port->gc;

View File

@ -467,10 +467,9 @@ static struct gpio_chip vr41xx_gpio_chip = {
static int giu_probe(struct platform_device *pdev)
{
struct resource *res;
unsigned int trigger, i, pin;
struct irq_chip *chip;
int irq, ret;
int irq;
switch (pdev->id) {
case GPIO_50PINS_PULLUPDOWN:
@ -489,21 +488,14 @@ static int giu_probe(struct platform_device *pdev)
return -ENODEV;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EBUSY;
giu_base = ioremap(res->start, resource_size(res));
if (!giu_base)
return -ENOMEM;
giu_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(giu_base))
return PTR_ERR(giu_base);
vr41xx_gpio_chip.parent = &pdev->dev;
ret = gpiochip_add_data(&vr41xx_gpio_chip, NULL);
if (!ret) {
iounmap(giu_base);
if (gpiochip_add_data(&vr41xx_gpio_chip, NULL))
return -ENODEV;
}
giu_write(GIUINTENL, 0);
giu_write(GIUINTENH, 0);
@ -534,7 +526,6 @@ static int giu_probe(struct platform_device *pdev)
static int giu_remove(struct platform_device *pdev)
{
if (giu_base) {
iounmap(giu_base);
giu_base = NULL;
}

View File

@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/io.h>
#include <linux/gpio/driver.h>
#include <linux/slab.h>
@ -33,14 +32,16 @@
/**
* struct xgpio_instance - Stores information about GPIO device
* @mmchip: OF GPIO chip for memory mapped banks
* @gc: GPIO chip
* @regs: register block
* @gpio_width: GPIO width for every channel
* @gpio_state: GPIO state shadow register
* @gpio_dir: GPIO direction shadow register
* @gpio_lock: Lock used for synchronization
*/
struct xgpio_instance {
struct of_mm_gpio_chip mmchip;
struct gpio_chip gc;
void __iomem *regs;
unsigned int gpio_width[2];
u32 gpio_state[2];
u32 gpio_dir[2];
@ -84,11 +85,10 @@ static inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
*/
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
u32 val;
val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET +
val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, gpio));
return !!(val & BIT(xgpio_offset(chip, gpio)));
@ -106,7 +106,6 @@ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
unsigned long flags;
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
@ -119,7 +118,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
else
chip->gpio_state[index] &= ~BIT(offset);
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
@ -138,7 +137,6 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
unsigned long *bits)
{
unsigned long flags;
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, 0);
int offset, i;
@ -150,7 +148,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
if (*mask == 0)
break;
if (index != xgpio_index(chip, i)) {
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, i),
chip->gpio_state[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
@ -166,7 +164,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
}
}
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, i), chip->gpio_state[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
@ -184,7 +182,6 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
unsigned long flags;
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
@ -193,7 +190,7 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
/* Set the GPIO bit in shadow register and set direction as input */
chip->gpio_dir[index] |= BIT(offset);
xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET +
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
@ -216,7 +213,6 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
unsigned long flags;
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
@ -228,12 +224,12 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
chip->gpio_state[index] |= BIT(offset);
else
chip->gpio_state[index] &= ~BIT(offset);
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
/* Clear the GPIO bit in shadow register and set direction as output */
chip->gpio_dir[index] &= ~BIT(offset);
xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET +
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
@ -243,42 +239,22 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
/**
* xgpio_save_regs - Set initial values of GPIO pins
* @mm_gc: Pointer to memory mapped GPIO chip structure
* @chip: Pointer to GPIO instance
*/
static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
static void xgpio_save_regs(struct xgpio_instance *chip)
{
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]);
xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]);
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
if (!chip->gpio_width[1])
return;
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
chip->gpio_state[1]);
xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
chip->gpio_dir[1]);
}
/**
* xgpio_remove - Remove method for the GPIO device.
* @pdev: pointer to the platform device
*
* This function remove gpiochips and frees all the allocated resources.
*
* Return: 0 always
*/
static int xgpio_remove(struct platform_device *pdev)
{
struct xgpio_instance *chip = platform_get_drvdata(pdev);
of_mm_gpiochip_remove(&chip->mmchip);
return 0;
}
/**
* xgpio_of_probe - Probe method for the GPIO device.
* @pdev: pointer to the platform device
@ -340,21 +316,28 @@ static int xgpio_probe(struct platform_device *pdev)
spin_lock_init(&chip->gpio_lock[1]);
}
chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
chip->mmchip.gc.parent = &pdev->dev;
chip->mmchip.gc.direction_input = xgpio_dir_in;
chip->mmchip.gc.direction_output = xgpio_dir_out;
chip->mmchip.gc.get = xgpio_get;
chip->mmchip.gc.set = xgpio_set;
chip->mmchip.gc.set_multiple = xgpio_set_multiple;
chip->gc.base = -1;
chip->gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
chip->gc.parent = &pdev->dev;
chip->gc.direction_input = xgpio_dir_in;
chip->gc.direction_output = xgpio_dir_out;
chip->gc.get = xgpio_get;
chip->gc.set = xgpio_set;
chip->gc.set_multiple = xgpio_set_multiple;
chip->mmchip.save_regs = xgpio_save_regs;
chip->gc.label = dev_name(&pdev->dev);
/* Call the OF gpio helper to setup and register the GPIO device */
status = of_mm_gpiochip_add_data(np, &chip->mmchip, chip);
chip->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(chip->regs)) {
dev_err(&pdev->dev, "failed to ioremap memory resource\n");
return PTR_ERR(chip->regs);
}
xgpio_save_regs(chip);
status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
if (status) {
pr_err("%pOF: error in probe function with status %d\n",
np, status);
dev_err(&pdev->dev, "failed to add GPIO chip\n");
return status;
}
@ -370,7 +353,6 @@ MODULE_DEVICE_TABLE(of, xgpio_of_match);
static struct platform_driver xgpio_plat_driver = {
.probe = xgpio_probe,
.remove = xgpio_remove,
.driver = {
.name = "gpio-xilinx",
.of_match_table = xgpio_of_match,

View File

@ -217,14 +217,13 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
if (!handler)
return AE_OK;
desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event", 0);
desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event",
GPIO_ACTIVE_HIGH, GPIOD_IN);
if (IS_ERR(desc)) {
dev_err(chip->parent, "Failed to request GPIO\n");
return AE_ERROR;
}
gpiod_direction_input(desc);
ret = gpiochip_lock_as_irq(chip, pin);
if (ret) {
dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
@ -951,6 +950,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
const char *label = "ACPI:OpRegion";
desc = gpiochip_request_own_desc(chip, pin, label,
GPIO_ACTIVE_HIGH,
flags);
if (IS_ERR(desc)) {
status = AE_ERROR;

View File

@ -165,6 +165,12 @@ static void of_gpio_flags_quirks(struct device_node *np,
}
}
}
/* Legacy handling of stmmac's active-low PHY reset line */
if (IS_ENABLED(CONFIG_STMMAC_ETH) &&
!strcmp(propname, "snps,reset-gpio") &&
of_property_read_bool(np, "snps,reset-active-low"))
*flags |= OF_GPIO_ACTIVE_LOW;
}
/**
@ -261,6 +267,37 @@ static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id
return desc;
}
/*
* The old Freescale bindings use simply "gpios" as name for the chip select
* lines rather than "cs-gpios" like all other SPI hardware. Account for this
* with a special quirk.
*/
static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev,
const char *con_id,
unsigned int idx,
unsigned long *flags)
{
struct device_node *np = dev->of_node;
if (!IS_ENABLED(CONFIG_SPI_MASTER))
return ERR_PTR(-ENOENT);
/* Allow this specifically for Freescale devices */
if (!of_device_is_compatible(np, "fsl,spi") &&
!of_device_is_compatible(np, "aeroflexgaisler,spictrl"))
return ERR_PTR(-ENOENT);
/* Allow only if asking for "cs-gpios" */
if (!con_id || strcmp(con_id, "cs"))
return ERR_PTR(-ENOENT);
/*
* While all other SPI controllers use "cs-gpios" the Freescale
* uses just "gpios" so translate to that when "cs-gpios" is
* requested.
*/
return of_find_gpio(dev, NULL, idx, flags);
}
/*
* Some regulator bindings happened before we managed to establish that GPIO
* properties should be named "foo-gpios" so we have this special kludge for
@ -332,6 +369,12 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
/* Special handling for SPI GPIOs if used */
if (IS_ERR(desc))
desc = of_find_spi_gpio(dev, con_id, &of_flags);
if (IS_ERR(desc)) {
/* This quirk looks up flags and all */
desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
if (!IS_ERR(desc))
return desc;
}
/* Special handling for regulator GPIOs if used */
if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)

View File

@ -1644,39 +1644,47 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
/**
* gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip chain to
* @gc: the gpiochip to set the irqchip chain to
* @parent_irq: the irq number corresponding to the parent IRQ for this
* chained irqchip
* @parent_handler: the parent interrupt handler for the accumulated IRQ
* coming out of the gpiochip. If the interrupt is nested rather than
* cascaded, pass NULL in this handler argument
*/
static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gc,
unsigned int parent_irq,
irq_flow_handler_t parent_handler)
{
if (!gpiochip->irq.domain) {
chip_err(gpiochip, "called %s before setting up irqchip\n",
struct gpio_irq_chip *girq = &gc->irq;
struct device *dev = &gc->gpiodev->dev;
if (!girq->domain) {
chip_err(gc, "called %s before setting up irqchip\n",
__func__);
return;
}
if (parent_handler) {
if (gpiochip->can_sleep) {
chip_err(gpiochip,
if (gc->can_sleep) {
chip_err(gc,
"you cannot have chained interrupts on a chip that may sleep\n");
return;
}
girq->parents = devm_kcalloc(dev, 1,
sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents) {
chip_err(gc, "out of memory allocating parent IRQ\n");
return;
}
girq->parents[0] = parent_irq;
girq->num_parents = 1;
/*
* The parent irqchip is already using the chip_data for this
* irqchip, so our callbacks simply use the handler_data.
*/
irq_set_chained_handler_and_data(parent_irq, parent_handler,
gpiochip);
gpiochip->irq.parent_irq = parent_irq;
gpiochip->irq.parents = &gpiochip->irq.parent_irq;
gpiochip->irq.num_parents = 1;
gc);
}
}
@ -2503,7 +2511,11 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
* @chip: GPIO chip
* @hwnum: hardware number of the GPIO for which to request the descriptor
* @label: label for the GPIO
* @flags: flags for this GPIO or 0 if default
* @lflags: lookup flags for this GPIO or 0 if default, this can be used to
* specify things like line inversion semantics with the machine flags
* such as GPIO_OUT_LOW
* @dflags: descriptor request flags for this GPIO or 0 if default, this
* can be used to specify consumer semantics such as open drain
*
* Function allows GPIO chip drivers to request and use their own GPIO
* descriptors via gpiolib API. Difference to gpiod_request() is that this
@ -2517,9 +2529,9 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
*/
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
const char *label,
enum gpiod_flags flags)
enum gpio_lookup_flags lflags,
enum gpiod_flags dflags)
{
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum);
int err;
@ -2532,7 +2544,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
if (err < 0)
return ERR_PTR(err);
err = gpiod_configure_flags(desc, label, lflags, flags);
err = gpiod_configure_flags(desc, label, lflags, dflags);
if (err) {
chip_err(chip, "setup of own GPIO %s failed\n", label);
gpiod_free_commit(desc);
@ -3019,13 +3031,13 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
* Return the GPIO's raw value, i.e. the value of the physical line disregarding
* its ACTIVE_LOW status, or negative errno on failure.
*
* This function should be called from contexts where we cannot sleep, and will
* This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
int gpiod_get_raw_value(const struct gpio_desc *desc)
{
VALIDATE_DESC(desc);
/* Should be using gpio_get_value_cansleep() */
/* Should be using gpiod_get_raw_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
return gpiod_get_raw_value_commit(desc);
}
@ -3038,7 +3050,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_value);
* Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into
* account, or negative errno on failure.
*
* This function should be called from contexts where we cannot sleep, and will
* This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
int gpiod_get_value(const struct gpio_desc *desc)
@ -3046,7 +3058,7 @@ int gpiod_get_value(const struct gpio_desc *desc)
int value;
VALIDATE_DESC(desc);
/* Should be using gpio_get_value_cansleep() */
/* Should be using gpiod_get_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
value = gpiod_get_raw_value_commit(desc);
@ -3071,7 +3083,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
* without regard for their ACTIVE_LOW status. Return 0 in case of success,
* else an error code.
*
* This function should be called from contexts where we cannot sleep,
* This function can be called from contexts where we cannot sleep,
* and it will complain if the GPIO chip functions potentially sleep.
*/
int gpiod_get_raw_array_value(unsigned int array_size,
@ -3097,7 +3109,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
* Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account. Return 0 in case of success, else an error code.
*
* This function should be called from contexts where we cannot sleep,
* This function can be called from contexts where we cannot sleep,
* and it will complain if the GPIO chip functions potentially sleep.
*/
int gpiod_get_array_value(unsigned int array_size,
@ -3311,13 +3323,13 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
* Set the raw value of the GPIO, i.e. the value of its physical line without
* regard for its ACTIVE_LOW status.
*
* This function should be called from contexts where we cannot sleep, and will
* This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
{
VALIDATE_DESC_VOID(desc);
/* Should be using gpiod_set_value_cansleep() */
/* Should be using gpiod_set_raw_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
gpiod_set_raw_value_commit(desc, value);
}
@ -3352,12 +3364,13 @@ static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value)
* Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW,
* OPEN_DRAIN and OPEN_SOURCE flags into account.
*
* This function should be called from contexts where we cannot sleep, and will
* This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
void gpiod_set_value(struct gpio_desc *desc, int value)
{
VALIDATE_DESC_VOID(desc);
/* Should be using gpiod_set_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
gpiod_set_value_nocheck(desc, value);
}
@ -3373,7 +3386,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
* Set the raw values of the GPIOs, i.e. the values of the physical lines
* without regard for their ACTIVE_LOW status.
*
* This function should be called from contexts where we cannot sleep, and will
* This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
int gpiod_set_raw_array_value(unsigned int array_size,
@ -3398,7 +3411,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
* Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account.
*
* This function should be called from contexts where we cannot sleep, and will
* This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
int gpiod_set_array_value(unsigned int array_size,
@ -4420,15 +4433,8 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
chip = gpiod_to_chip(desc);
hwnum = gpio_chip_hwgpio(desc);
/*
* FIXME: not very elegant that we call gpiod_configure_flags()
* twice here (once inside gpiochip_request_own_desc() and
* again here), but the gpiochip_request_own_desc() is external
* and cannot really pass the lflags so this is the lesser evil
* at the moment. Pass zero as dflags on this first call so we
* don't screw anything up.
*/
local_desc = gpiochip_request_own_desc(chip, hwnum, name, 0);
local_desc = gpiochip_request_own_desc(chip, hwnum, name,
lflags, dflags);
if (IS_ERR(local_desc)) {
status = PTR_ERR(local_desc);
pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n",
@ -4436,14 +4442,6 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
return status;
}
status = gpiod_configure_flags(desc, name, lflags, dflags);
if (status < 0) {
pr_err("setup of hog GPIO %s (chip %s, offset %d) failed, %d\n",
name, chip->label, hwnum, status);
gpiochip_free_own_desc(desc);
return status;
}
/* Mark GPIO as hogged so it can be identified and removed later */
set_bit(FLAG_IS_HOGGED, &desc->flags);
@ -4805,8 +4803,8 @@ static const struct file_operations gpiolib_operations = {
static int __init gpiolib_debugfs_init(void)
{
/* /sys/kernel/debug/gpio */
(void) debugfs_create_file("gpio", S_IFREG | S_IRUGO,
NULL, NULL, &gpiolib_operations);
debugfs_create_file("gpio", S_IFREG | S_IRUGO, NULL, NULL,
&gpiolib_operations);
return 0;
}
subsys_initcall(gpiolib_debugfs_init);

View File

@ -210,7 +210,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
struct gpio_array *array_info,
unsigned long *value_bitmap);
extern struct spinlock gpio_lock;
extern spinlock_t gpio_lock;
extern struct list_head gpio_devices;
struct gpio_desc {

View File

@ -16,7 +16,8 @@
* https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf
*/
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/driver.h>
#include <linux/hid.h>
#include <linux/hidraw.h>
@ -1195,7 +1196,9 @@ static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
return -EINVAL;
dev->desc[pin] = gpiochip_request_own_desc(&dev->gc, pin,
"HID/I2C:Event", 0);
"HID/I2C:Event",
GPIO_ACTIVE_HIGH,
GPIOD_IN);
if (IS_ERR(dev->desc[pin])) {
dev_err(dev->gc.parent, "Failed to request GPIO\n");
return PTR_ERR(dev->desc[pin]);

View File

@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h> /* GPIO descriptor enum */
#include <linux/gpio/machine.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/platform_device.h>
@ -2169,7 +2170,8 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
wait_pin, "WAITPIN",
0);
GPIO_ACTIVE_HIGH,
GPIOD_IN);
if (IS_ERR(waitpin_desc)) {
dev_err(&pdev->dev, "invalid wait-pin: %d\n", wait_pin);
ret = PTR_ERR(waitpin_desc);

View File

@ -1,39 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This file is separate from sdb.h, because I want that one to remain
* unchanged (as far as possible) from the official sdb distribution
*
* This file and associated functionality are a playground for me to
* understand stuff which will later be implemented in more generic places.
*/
#include <linux/sdb.h>
/* This is the union of all currently defined types */
union sdb_record {
struct sdb_interconnect ic;
struct sdb_device dev;
struct sdb_bridge bridge;
struct sdb_integration integr;
struct sdb_empty empty;
struct sdb_synthesis synthesis;
struct sdb_repo_url repo_url;
};
struct fmc_device;
/* Every sdb table is turned into this structure */
struct sdb_array {
int len;
int level;
unsigned long baseaddr;
struct fmc_device *fmc; /* the device that hosts it */
struct sdb_array *parent; /* NULL at root */
union sdb_record *record; /* copies of the struct */
struct sdb_array **subtree; /* only valid for bridge items */
};
extern int fmc_scan_sdb_tree(struct fmc_device *fmc, unsigned long address);
extern void fmc_show_sdb_tree(const struct fmc_device *fmc);
extern signed long fmc_find_sdb_device(struct sdb_array *tree, uint64_t vendor,
uint32_t device, unsigned long *sz);
extern int fmc_free_sdb_tree(struct fmc_device *fmc);

View File

@ -1,269 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __LINUX_FMC_H__
#define __LINUX_FMC_H__
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/io.h>
struct fmc_device;
struct fmc_driver;
/*
* This bus abstraction is developed separately from drivers, so we need
* to check the version of the data structures we receive.
*/
#define FMC_MAJOR 3
#define FMC_MINOR 0
#define FMC_VERSION ((FMC_MAJOR << 16) | FMC_MINOR)
#define __FMC_MAJOR(x) ((x) >> 16)
#define __FMC_MINOR(x) ((x) & 0xffff)
/*
* The device identification, as defined by the IPMI FRU (Field Replaceable
* Unit) includes four different strings to describe the device. Here we
* only match the "Board Manufacturer" and the "Board Product Name",
* ignoring the "Board Serial Number" and "Board Part Number". All 4 are
* expected to be strings, so they are treated as zero-terminated C strings.
* Unspecified string (NULL) means "any", so if both are unspecified this
* is a catch-all driver. So null entries are allowed and we use array
* and length. This is unlike pci and usb that use null-terminated arrays
*/
struct fmc_fru_id {
char *manufacturer;
char *product_name;
};
/*
* If the FPGA is already programmed (think Etherbone or the second
* SVEC slot), we can match on SDB devices in the memory image. This
* match uses an array of devices that must all be present, and the
* match is based on vendor and device only. Further checks are expected
* to happen in the probe function. Zero means "any" and catch-all is allowed.
*/
struct fmc_sdb_one_id {
uint64_t vendor;
uint32_t device;
};
struct fmc_sdb_id {
struct fmc_sdb_one_id *cores;
int cores_nr;
};
struct fmc_device_id {
struct fmc_fru_id *fru_id;
int fru_id_nr;
struct fmc_sdb_id *sdb_id;
int sdb_id_nr;
};
/* This sizes the module_param_array used by generic module parameters */
#define FMC_MAX_CARDS 32
/* The driver is a pretty simple thing */
struct fmc_driver {
unsigned long version;
struct device_driver driver;
int (*probe)(struct fmc_device *);
int (*remove)(struct fmc_device *);
const struct fmc_device_id id_table;
/* What follows is for generic module parameters */
int busid_n;
int busid_val[FMC_MAX_CARDS];
int gw_n;
char *gw_val[FMC_MAX_CARDS];
};
#define to_fmc_driver(x) container_of((x), struct fmc_driver, driver)
/* These are the generic parameters, that drivers may instantiate */
#define FMC_PARAM_BUSID(_d) \
module_param_array_named(busid, _d.busid_val, int, &_d.busid_n, 0444)
#define FMC_PARAM_GATEWARE(_d) \
module_param_array_named(gateware, _d.gw_val, charp, &_d.gw_n, 0444)
/*
* Drivers may need to configure gpio pins in the carrier. To read input
* (a very uncommon operation, and definitely not in the hot paths), just
* configure one gpio only and get 0 or 1 as retval of the config method
*/
struct fmc_gpio {
char *carrier_name; /* name or NULL for virtual pins */
int gpio;
int _gpio; /* internal use by the carrier */
int mode; /* GPIOF_DIR_OUT etc, from <linux/gpio.h> */
int irqmode; /* IRQF_TRIGGER_LOW and so on */
};
/* The numbering of gpio pins allows access to raw pins or virtual roles */
#define FMC_GPIO_RAW(x) (x) /* 4096 of them */
#define __FMC_GPIO_IS_RAW(x) ((x) < 0x1000)
#define FMC_GPIO_IRQ(x) ((x) + 0x1000) /* 256 of them */
#define FMC_GPIO_LED(x) ((x) + 0x1100) /* 256 of them */
#define FMC_GPIO_KEY(x) ((x) + 0x1200) /* 256 of them */
#define FMC_GPIO_TP(x) ((x) + 0x1300) /* 256 of them */
#define FMC_GPIO_USER(x) ((x) + 0x1400) /* 256 of them */
/* We may add SCL and SDA, or other roles if the need arises */
/* GPIOF_DIR_IN etc are missing before 3.0. copy from <linux/gpio.h> */
#ifndef GPIOF_DIR_IN
# define GPIOF_DIR_OUT (0 << 0)
# define GPIOF_DIR_IN (1 << 0)
# define GPIOF_INIT_LOW (0 << 1)
# define GPIOF_INIT_HIGH (1 << 1)
#endif
/*
* The operations are offered by each carrier and should make driver
* design completely independent of the carrier. Named GPIO pins may be
* the exception.
*/
struct fmc_operations {
uint32_t (*read32)(struct fmc_device *fmc, int offset);
void (*write32)(struct fmc_device *fmc, uint32_t value, int offset);
int (*validate)(struct fmc_device *fmc, struct fmc_driver *drv);
int (*reprogram_raw)(struct fmc_device *f, struct fmc_driver *d,
void *gw, unsigned long len);
int (*reprogram)(struct fmc_device *f, struct fmc_driver *d, char *gw);
int (*irq_request)(struct fmc_device *fmc, irq_handler_t h,
char *name, int flags);
void (*irq_ack)(struct fmc_device *fmc);
int (*irq_free)(struct fmc_device *fmc);
int (*gpio_config)(struct fmc_device *fmc, struct fmc_gpio *gpio,
int ngpio);
int (*read_ee)(struct fmc_device *fmc, int pos, void *d, int l);
int (*write_ee)(struct fmc_device *fmc, int pos, const void *d, int l);
};
/* Prefer this helper rather than calling of fmc->reprogram directly */
int fmc_reprogram_raw(struct fmc_device *fmc, struct fmc_driver *d,
void *gw, unsigned long len, int sdb_entry);
extern int fmc_reprogram(struct fmc_device *f, struct fmc_driver *d, char *gw,
int sdb_entry);
/*
* The device reports all information needed to access hw.
*
* If we have eeprom_len and not contents, the core reads it.
* Then, parsing of identifiers is done by the core which fills fmc_fru_id..
* Similarly a device that must be matched based on SDB cores must
* fill the entry point and the core will scan the bus (FIXME: sdb match)
*/
struct fmc_device {
unsigned long version;
unsigned long flags;
struct module *owner; /* char device must pin it */
struct fmc_fru_id id; /* for EEPROM-based match */
struct fmc_operations *op; /* carrier-provided */
int irq; /* according to host bus. 0 == none */
int eeprom_len; /* Usually 8kB, may be less */
int eeprom_addr; /* 0x50, 0x52 etc */
uint8_t *eeprom; /* Full contents or leading part */
char *carrier_name; /* "SPEC" or similar, for special use */
void *carrier_data; /* "struct spec *" or equivalent */
__iomem void *fpga_base; /* May be NULL (Etherbone) */
__iomem void *slot_base; /* Set by the driver */
struct fmc_device **devarray; /* Allocated by the bus */
int slot_id; /* Index in the slot array */
int nr_slots; /* Number of slots in this carrier */
unsigned long memlen; /* Used for the char device */
struct device dev; /* For Linux use */
struct device *hwdev; /* The underlying hardware device */
unsigned long sdbfs_entry;
struct sdb_array *sdb;
uint32_t device_id; /* Filled by the device */
char *mezzanine_name; /* Defaults to ``fmc'' */
void *mezzanine_data;
struct dentry *dbg_dir;
struct dentry *dbg_sdb_dump;
};
#define to_fmc_device(x) container_of((x), struct fmc_device, dev)
#define FMC_DEVICE_HAS_GOLDEN 1
#define FMC_DEVICE_HAS_CUSTOM 2
#define FMC_DEVICE_NO_MEZZANINE 4
#define FMC_DEVICE_MATCH_SDB 8 /* fmc-core must scan sdb in fpga */
/*
* If fpga_base can be used, the carrier offers no readl/writel methods, and
* this expands to a single, fast, I/O access.
*/
static inline uint32_t fmc_readl(struct fmc_device *fmc, int offset)
{
if (unlikely(fmc->op->read32))
return fmc->op->read32(fmc, offset);
return readl(fmc->fpga_base + offset);
}
static inline void fmc_writel(struct fmc_device *fmc, uint32_t val, int off)
{
if (unlikely(fmc->op->write32))
fmc->op->write32(fmc, val, off);
else
writel(val, fmc->fpga_base + off);
}
/* pci-like naming */
static inline void *fmc_get_drvdata(const struct fmc_device *fmc)
{
return dev_get_drvdata(&fmc->dev);
}
static inline void fmc_set_drvdata(struct fmc_device *fmc, void *data)
{
dev_set_drvdata(&fmc->dev, data);
}
struct fmc_gateware {
void *bitstream;
unsigned long len;
};
/* The 5 access points */
extern int fmc_driver_register(struct fmc_driver *drv);
extern void fmc_driver_unregister(struct fmc_driver *drv);
extern int fmc_device_register(struct fmc_device *tdev);
extern int fmc_device_register_gw(struct fmc_device *tdev,
struct fmc_gateware *gw);
extern void fmc_device_unregister(struct fmc_device *tdev);
/* Three more for device sets, all driven by the same FPGA */
extern int fmc_device_register_n(struct fmc_device **devs, int n);
extern int fmc_device_register_n_gw(struct fmc_device **devs, int n,
struct fmc_gateware *gw);
extern void fmc_device_unregister_n(struct fmc_device **devs, int n);
/* Internal cross-calls between files; not exported to other modules */
extern int fmc_match(struct device *dev, struct device_driver *drv);
extern int fmc_fill_id_info(struct fmc_device *fmc);
extern void fmc_free_id_info(struct fmc_device *fmc);
extern void fmc_dump_eeprom(const struct fmc_device *fmc);
/* helpers for FMC operations */
extern int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h,
char *name, int flags);
extern void fmc_irq_free(struct fmc_device *fmc);
extern void fmc_irq_ack(struct fmc_device *fmc);
extern int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv);
extern int fmc_gpio_config(struct fmc_device *fmc, struct fmc_gpio *gpio,
int ngpio);
extern int fmc_read_ee(struct fmc_device *fmc, int pos, void *d, int l);
extern int fmc_write_ee(struct fmc_device *fmc, int pos, const void *d, int l);
/* helpers for FMC operations */
extern int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h,
char *name, int flags);
extern void fmc_irq_free(struct fmc_device *fmc);
extern void fmc_irq_ack(struct fmc_device *fmc);
extern int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv);
#endif /* __LINUX_FMC_H__ */

View File

@ -18,6 +18,7 @@ struct seq_file;
struct gpio_device;
struct module;
enum gpiod_flags;
enum gpio_lookup_flags;
#ifdef CONFIG_GPIOLIB
@ -101,13 +102,6 @@ struct gpio_irq_chip {
*/
unsigned int num_parents;
/**
* @parent_irq:
*
* For use by gpiochip_set_cascaded_irqchip()
*/
unsigned int parent_irq;
/**
* @parents:
*
@ -167,7 +161,7 @@ struct gpio_irq_chip {
*/
void (*irq_disable)(struct irq_data *data);
};
#endif
#endif /* CONFIG_GPIOLIB_IRQCHIP */
/**
* struct gpio_chip - abstract a GPIO controller
@ -200,6 +194,8 @@ struct gpio_irq_chip {
* @dbg_show: optional routine to show contents in debugfs; default code
* will be used when this is omitted, but custom code can show extra
* state (such as pullup/pulldown configuration).
* @init_valid_mask: optional routine to initialize @valid_mask, to be used if
* not all GPIOs are valid.
* @base: identifies the first GPIO number handled by this chip;
* or, if negative during registration, requests dynamic ID allocation.
* DEPRECATION: providing anything non-negative and nailing the base
@ -307,7 +303,7 @@ struct gpio_chip {
spinlock_t bgpio_lock;
unsigned long bgpio_data;
unsigned long bgpio_dir;
#endif
#endif /* CONFIG_GPIO_GENERIC */
#ifdef CONFIG_GPIOLIB_IRQCHIP
/*
@ -322,7 +318,7 @@ struct gpio_chip {
* used to handle IRQs for most practical cases.
*/
struct gpio_irq_chip irq;
#endif
#endif /* CONFIG_GPIOLIB_IRQCHIP */
/**
* @need_valid_mask:
@ -369,7 +365,7 @@ struct gpio_chip {
*/
int (*of_xlate)(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags);
#endif
#endif /* CONFIG_OF_GPIO */
};
extern const char *gpiochip_is_requested(struct gpio_chip *chip,
@ -412,7 +408,7 @@ extern int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
})
#else
#define gpiochip_add_data(chip, data) gpiochip_add_data_with_key(chip, data, NULL, NULL)
#endif
#endif /* CONFIG_LOCKDEP */
static inline int gpiochip_add(struct gpio_chip *chip)
{
@ -467,7 +463,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
#define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */
#define BGPIOF_NO_OUTPUT BIT(5) /* only input */
#endif
#endif /* CONFIG_GPIO_GENERIC */
#ifdef CONFIG_GPIOLIB_IRQCHIP
@ -537,7 +533,7 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
handler, type, true,
&lock_key, &request_key);
}
#else
#else /* ! CONFIG_LOCKDEP */
static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
struct irq_chip *irqchip,
unsigned int first_irq,
@ -588,7 +584,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip,
unsigned int gpio_offset, const char *pin_group);
void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
#else
#else /* ! CONFIG_PINCTRL */
static inline int
gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
@ -614,7 +610,8 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip)
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
const char *label,
enum gpiod_flags flags);
enum gpio_lookup_flags lflags,
enum gpiod_flags dflags);
void gpiochip_free_own_desc(struct gpio_desc *desc);
void devprop_gpiochip_set_names(struct gpio_chip *chip,

View File

@ -11,4 +11,4 @@ struct gpio_chip *gpio_reg_init(struct device *dev, void __iomem *reg,
int gpio_reg_resume(struct gpio_chip *gc);
#endif
#endif /* GPIO_REG_H */

View File

@ -97,7 +97,7 @@ void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n);
void gpiod_remove_lookup_table(struct gpiod_lookup_table *table);
void gpiod_add_hogs(struct gpiod_hog *hogs);
#else
#else /* ! CONFIG_GPIOLIB */
static inline
void gpiod_add_lookup_table(struct gpiod_lookup_table *table) {}
static inline
@ -105,6 +105,6 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) {}
static inline
void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) {}
static inline void gpiod_add_hogs(struct gpiod_hog *hogs) {}
#endif
#endif /* CONFIG_GPIOLIB */
#endif /* __LINUX_GPIO_MACHINE_H */

View File

@ -186,7 +186,7 @@ struct omap_gpio_platform_data {
bool is_mpuio; /* whether the bank is of type MPUIO */
u32 non_wakeup_gpios;
struct omap_gpio_reg_offs *regs;
const struct omap_gpio_reg_offs *regs;
/* Return context loss count due to PM states changing */
int (*get_context_loss_count)(struct device *dev);

View File

@ -72,3 +72,13 @@ static inline void siox_driver_unregister(struct siox_driver *sdriver)
{
return driver_unregister(&sdriver->driver);
}
/*
* module_siox_driver() - Helper macro for drivers that don't do
* anything special in module init/exit. This eliminates a lot of
* boilerplate. Each module may only use this macro once, and
* calling it replaces module_init() and module_exit()
*/
#define module_siox_driver(__siox_driver) \
module_driver(__siox_driver, siox_driver_register, \
siox_driver_unregister)

View File

@ -1,4 +1,4 @@
gpio-event-mon
gpio-hammer
lsgpio
include/linux/gpio.h