* [PATCH RFC 00/15 v5] gpio: Add block GPIO
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
This set of patches adds:
* Block GPIO API to gpiolib
* Sysfs support for GPIO API, to provide userland access
* Devicetree support to instantiate GPIO blocks via DT
* Example implementations in several gpio drivers since they need
special accessor functions for block wise GPIO access
* Fix for race condition in gpiolib on device creation
Signed-off-by: Roland Stigge <stigge@antcom.de>
--
Changes since v4:
* Documented word width
* Bugfix: export/unexport on register/unregister
* Using default dev_attrs for gpio_block_class
* Fix gpiolib: race condition on device creation
* Added driver support for ucb14500, vt8500, xilinx
Changes since v3:
* Added driver support for pca953x, em, pl061, max732x, pcf857x
* Coding style improvements
* Fixed krealloc memory leak in error case
* sysfs: values in hex
* Register blocks in a list
* Narrowing lock scope
* Use S_IWUSR and S_IRUGO instead of direct octal values
* Use for_each_set_bit()
* Change from unsigned to unsigned long for masks and values
Changes since v2:
* Added sysfs support
* Added devicetree support
* Added support for lpc32xx, generic
* Added functions for GPIO block registration
* Added more error checking
* Bit remapping bugfix
Changes since v1:
* API change to 32/64 bit word, bit masks
Thanks to Ryan Mallon, Linus Walleij, Stijn Devriendt, Jean-Christophe
Plagniol-Villard, Mark Brown and Greg Kroah-Hartman for reviewing!
Roland Stigge (15):
gpio: Add a block GPIO API to gpiolib
gpio: Add sysfs support to block GPIO API
gpiolib: Fix default attributes for class
gpio: Add device tree support to block GPIO API
gpio-max730x: Add block GPIO API
gpio-lpc32xx: Add block GPIO API
gpio-generic: Add block GPIO API
gpio-pca953x: Add block GPIO API
gpio-em: Add block GPIO API
gpio-pl061: Add block GPIO API
gpio-max732x: Add block GPIO API
gpio-pcf857x: Add block GPIO API
gpio-xilinx: Add block GPIO API
gpio-vt8500: Add block GPIO API
gpio-ucb1400: Add block GPIO API
Documentation/ABI/testing/sysfs-gpio | 6
Documentation/devicetree/bindings/gpio/gpio-block.txt | 36 +
Documentation/gpio.txt | 47 +
drivers/gpio/Makefile | 1
drivers/gpio/gpio-em.c | 23
drivers/gpio/gpio-generic.c | 56 +
drivers/gpio/gpio-lpc32xx.c | 82 ++
drivers/gpio/gpio-max730x.c | 61 ++
drivers/gpio/gpio-max732x.c | 59 ++
drivers/gpio/gpio-pca953x.c | 64 ++
drivers/gpio/gpio-pcf857x.c | 24
drivers/gpio/gpio-pl061.c | 17
drivers/gpio/gpio-ucb1400.c | 23
drivers/gpio/gpio-vt8500.c | 24
drivers/gpio/gpio-xilinx.c | 44 +
drivers/gpio/gpioblock-of.c | 84 ++
drivers/gpio/gpiolib.c | 510 ++++++++++++++++--
include/asm-generic/gpio.h | 26
include/linux/gpio.h | 87 +++
19 files changed, 1228 insertions(+), 46 deletions(-)
^ permalink raw reply
* [PATCH RFC 01/15 v5] gpio: Add a block GPIO API to gpiolib
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
The recurring task of providing simultaneous access to GPIO lines (especially
for bit banging protocols) needs an appropriate API.
This patch adds a kernel internal "Block GPIO" API that enables simultaneous
access to several GPIOs. This is done by abstracting GPIOs to an n-bit word:
Once requested, it provides access to a group of GPIOs which can range over
multiple GPIO chips.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
Documentation/gpio.txt | 47 +++++++++
drivers/gpio/gpiolib.c | 217 +++++++++++++++++++++++++++++++++++++++++++++
include/asm-generic/gpio.h | 15 +++
include/linux/gpio.h | 74 +++++++++++++++
4 files changed, 353 insertions(+)
--- linux-2.6.orig/Documentation/gpio.txt
+++ linux-2.6/Documentation/gpio.txt
@@ -439,6 +439,53 @@ slower clock delays the rising edge of S
signaling rate accordingly.
+Block GPIO
+----------
+
+The above described interface concentrates on handling single GPIOs. However,
+in applications where it is critical to set several GPIOs at once, this
+interface doesn't work well, e.g. bit-banging protocols via grouped GPIO lines.
+Consider a GPIO controller that is connected via a slow I2C line. When
+switching two or more GPIOs one after another, there can be considerable time
+between those events. This is solved by an interface called Block GPIO:
+
+struct gpio_block *gpio_block_create(unsigned int *gpios, size_t size);
+
+This creates a new block of GPIOs as a list of GPIO numbers with the specified
+size which are accessible via the returned struct gpio_block and the accessor
+functions described below. Please note that you need to request the GPIOs
+separately via gpio_request(). An arbitrary list of globally valid GPIOs can be
+specified, even ranging over several gpio_chips. Actual handling of I/O
+operations will be done on a best effort base, i.e. simultaneous I/O only where
+possible by hardware and implemented in the respective GPIO driver. The number
+of GPIOs in one block is limited to the number of bits in an unsigned long, or
+BITS_PER_LONG, of the respective platform, i.e. typically at least 32 on a 32
+bit system, and at least 64 on a 64 bit system. However, several blocks can be
+defined at once.
+
+unsigned gpio_block_get(struct gpio_block *block);
+void gpio_block_set(struct gpio_block *block, unsigned value);
+
+With those accessor functions, setting and getting the GPIO values is possible,
+analogous to gpio_get_value() and gpio_set_value(). Each bit in the return
+value of gpio_block_get() and in the value argument of gpio_block_set()
+corresponds to a bit specified on gpio_block_create(). Block operations in
+hardware are only possible where the respective GPIO driver implements it,
+falling back to using single GPIO operations where the driver only implements
+single GPIO access.
+
+void gpio_block_free(struct gpio_block *block);
+
+After the GPIO block isn't used anymore, it should be free'd via
+gpio_block_free().
+
+int gpio_block_register(struct gpio_block *block);
+void gpio_block_unregister(struct gpio_block *block);
+
+These functions can be used to register a GPIO block. Blocks registered this
+way will be available via sysfs.
+
+
What do these conventions omit?
===============================
One of the biggest things these conventions omit is pin multiplexing, since
--- linux-2.6.orig/drivers/gpio/gpiolib.c
+++ linux-2.6/drivers/gpio/gpiolib.c
@@ -83,6 +83,8 @@ static inline void desc_set_label(struct
#endif
}
+static LIST_HEAD(gpio_block_list);
+
/* Warn when drivers omit gpio_request() calls -- legal but ill-advised
* when setting direction, and otherwise illegal. Until board setup code
* and drivers use explicit requests everywhere (which won't happen when
@@ -1676,6 +1678,221 @@ void __gpio_set_value(unsigned gpio, int
}
EXPORT_SYMBOL_GPL(__gpio_set_value);
+static int gpio_block_chip_index(struct gpio_block *block, struct gpio_chip *gc)
+{
+ int i;
+
+ for (i = 0; i < block->nchip; i++) {
+ if (block->gbc[i].gc == gc)
+ return i;
+ }
+ return -1;
+}
+
+struct gpio_block *gpio_block_create(unsigned *gpios, size_t size,
+ const char *name)
+{
+ struct gpio_block *block;
+ struct gpio_block_chip *gbc;
+ struct gpio_remap *remap;
+ void *tmp;
+ int i;
+
+ if (size < 1 || size > sizeof(unsigned long) * 8)
+ return ERR_PTR(-EINVAL);
+
+ for (i = 0; i < size; i++)
+ if (!gpio_is_valid(gpios[i]))
+ return ERR_PTR(-EINVAL);
+
+ block = kzalloc(sizeof(struct gpio_block), GFP_KERNEL);
+ if (!block)
+ return ERR_PTR(-ENOMEM);
+
+ block->name = name;
+ block->ngpio = size;
+ block->gpio = kzalloc(sizeof(*block->gpio) * size, GFP_KERNEL);
+ if (!block->gpio)
+ goto err1;
+
+ memcpy(block->gpio, gpios, sizeof(*block->gpio) * size);
+
+ for (i = 0; i < size; i++) {
+ struct gpio_chip *gc = gpio_to_chip(gpios[i]);
+ int bit = gpios[i] - gc->base;
+ int index = gpio_block_chip_index(block, gc);
+
+ if (index < 0) {
+ block->nchip++;
+ tmp = krealloc(block->gbc,
+ sizeof(struct gpio_block_chip) *
+ block->nchip, GFP_KERNEL);
+ if (!tmp) {
+ kfree(block->gbc);
+ goto err2;
+ }
+ block->gbc = tmp;
+ gbc = &block->gbc[block->nchip - 1];
+ gbc->gc = gc;
+ gbc->remap = NULL;
+ gbc->nremap = 0;
+ gbc->mask = 0;
+ } else {
+ gbc = &block->gbc[index];
+ }
+ /* represents the mask necessary on calls to the driver's
+ * .get_block() and .set_block()
+ */
+ gbc->mask |= BIT(bit);
+
+ /* collect gpios that are specified together, represented by
+ * neighboring bits
+ *
+ * Note that even though in setting remap is given a negative
+ * index, the next lines guard that the potential out-of-bounds
+ * pointer is not dereferenced when out of bounds.
+ */
+ remap = &gbc->remap[gbc->nremap - 1];
+ if (!gbc->nremap || (bit - i != remap->offset)) {
+ gbc->nremap++;
+ tmp = krealloc(gbc->remap,
+ sizeof(struct gpio_remap) *
+ gbc->nremap, GFP_KERNEL);
+ if (!tmp) {
+ kfree(gbc->remap);
+ goto err3;
+ }
+ gbc->remap = tmp;
+ remap = &gbc->remap[gbc->nremap - 1];
+ remap->offset = bit - i;
+ remap->mask = 0;
+ }
+
+ /* represents the mask necessary for bit reordering between
+ * gpio_block (i.e. as specified on gpio_block_get() and
+ * gpio_block_set()) and gpio_chip domain (i.e. as specified on
+ * the driver's .set_block() and .get_block())
+ */
+ remap->mask |= BIT(i);
+ }
+
+ return block;
+err3:
+ for (i = 0; i < block->nchip - 1; i++)
+ kfree(block->gbc[i].remap);
+ kfree(block->gbc);
+err2:
+ kfree(block->gpio);
+err1:
+ kfree(block);
+ return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL_GPL(gpio_block_create);
+
+void gpio_block_free(struct gpio_block *block)
+{
+ int i;
+
+ for (i = 0; i < block->nchip; i++)
+ kfree(block->gbc[i].remap);
+ kfree(block->gpio);
+ kfree(block->gbc);
+ kfree(block);
+}
+EXPORT_SYMBOL_GPL(gpio_block_free);
+
+unsigned long gpio_block_get(const struct gpio_block *block)
+{
+ struct gpio_block_chip *gbc;
+ int i, j;
+ unsigned long values = 0;
+
+ for (i = 0; i < block->nchip; i++) {
+ unsigned long remapped = 0;
+
+ gbc = &block->gbc[i];
+
+ if (gbc->gc->get_block) {
+ remapped = gbc->gc->get_block(gbc->gc, gbc->mask);
+ } else {
+ /* emulate */
+ for_each_set_bit(j, &gbc->mask, BITS_PER_LONG)
+ remapped |= gbc->gc->get(gbc->gc,
+ gbc->gc->base + j) << j;
+ }
+
+ for (j = 0; j < gbc->nremap; j++) {
+ struct gpio_remap *gr = &gbc->remap[j];
+
+ values |= (remapped >> gr->offset) & gr->mask;
+ }
+ }
+
+ return values;
+}
+EXPORT_SYMBOL_GPL(gpio_block_get);
+
+void gpio_block_set(struct gpio_block *block, unsigned long values)
+{
+ struct gpio_block_chip *gbc;
+ int i, j;
+
+ for (i = 0; i < block->nchip; i++) {
+ unsigned long remapped = 0;
+
+ gbc = &block->gbc[i];
+
+ for (j = 0; j < gbc->nremap; j++) {
+ struct gpio_remap *gr = &gbc->remap[j];
+
+ remapped |= (values & gr->mask) << gr->offset;
+ }
+ if (gbc->gc->set_block) {
+ gbc->gc->set_block(gbc->gc, gbc->mask, remapped);
+ } else {
+ /* emulate */
+ for_each_set_bit(j, &gbc->mask, BITS_PER_LONG)
+ gbc->gc->set(gbc->gc, gbc->gc->base + j,
+ (remapped >> j) & 1);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(gpio_block_set);
+
+struct gpio_block *gpio_block_find_by_name(const char *name)
+{
+ struct gpio_block *i;
+
+ list_for_each_entry(i, &gpio_block_list, list)
+ if (!strcmp(i->name, name))
+ return i;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(gpio_block_find_by_name);
+
+int gpio_block_register(struct gpio_block *block)
+{
+ if (gpio_block_find_by_name(block->name))
+ return -EBUSY;
+
+ list_add(&block->list, &gpio_block_list);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_block_register);
+
+void gpio_block_unregister(struct gpio_block *block)
+{
+ struct gpio_block *i;
+
+ list_for_each_entry(i, &gpio_block_list, list)
+ if (i == block) {
+ list_del(&i->list);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(gpio_block_unregister);
+
/**
* __gpio_cansleep() - report whether gpio value access will sleep
* @gpio: gpio in question
--- linux-2.6.orig/include/asm-generic/gpio.h
+++ linux-2.6/include/asm-generic/gpio.h
@@ -43,6 +43,7 @@ static inline bool gpio_is_valid(int num
struct device;
struct gpio;
+struct gpio_block;
struct seq_file;
struct module;
struct device_node;
@@ -105,6 +106,8 @@ struct gpio_chip {
unsigned offset);
int (*get)(struct gpio_chip *chip,
unsigned offset);
+ unsigned long (*get_block)(struct gpio_chip *chip,
+ unsigned long mask);
int (*direction_output)(struct gpio_chip *chip,
unsigned offset, int value);
int (*set_debounce)(struct gpio_chip *chip,
@@ -112,6 +115,9 @@ struct gpio_chip {
void (*set)(struct gpio_chip *chip,
unsigned offset, int value);
+ void (*set_block)(struct gpio_chip *chip,
+ unsigned long mask,
+ unsigned long values);
int (*to_irq)(struct gpio_chip *chip,
unsigned offset);
@@ -171,6 +177,15 @@ extern void gpio_set_value_cansleep(unsi
extern int __gpio_get_value(unsigned gpio);
extern void __gpio_set_value(unsigned gpio, int value);
+extern struct gpio_block *gpio_block_create(unsigned *gpio, size_t size,
+ const char *name);
+extern void gpio_block_free(struct gpio_block *block);
+extern unsigned long gpio_block_get(const struct gpio_block *block);
+extern void gpio_block_set(struct gpio_block *block, unsigned long values);
+extern struct gpio_block *gpio_block_find_by_name(const char *name);
+extern int gpio_block_register(struct gpio_block *block);
+extern void gpio_block_unregister(struct gpio_block *block);
+
extern int __gpio_cansleep(unsigned gpio);
extern int __gpio_to_irq(unsigned gpio);
--- linux-2.6.orig/include/linux/gpio.h
+++ linux-2.6/include/linux/gpio.h
@@ -2,6 +2,8 @@
#define __LINUX_GPIO_H
#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/list.h>
/* see Documentation/gpio.txt */
@@ -39,6 +41,43 @@ struct gpio {
const char *label;
};
+/*
+ * struct gpio_remap - a structure for describing a bit mapping
+ * @mask: a bit mask
+ * @offset: how many bits to shift to the left (negative: to the right)
+ *
+ * When we are mapping bit values from one word to another (here: from GPIO
+ * block domain to GPIO driver domain) we first mask them out with mask and
+ * shift them as specified with offset. More complicated mappings are done by
+ * grouping several of those structs and adding the results together.
+ */
+struct gpio_remap {
+ unsigned long mask;
+ int offset;
+};
+
+struct gpio_block_chip {
+ struct gpio_chip *gc;
+ struct gpio_remap *remap;
+ int nremap;
+ unsigned long mask;
+};
+
+/**
+ * struct gpio_block - a structure describing a list of GPIOs for simultaneous
+ * operations
+ */
+struct gpio_block {
+ struct gpio_block_chip *gbc;
+ size_t nchip;
+ const char *name;
+
+ int ngpio;
+ unsigned *gpio;
+
+ struct list_head list;
+};
+
#ifdef CONFIG_GENERIC_GPIO
#ifdef CONFIG_ARCH_HAVE_CUSTOM_GPIO_H
@@ -169,6 +208,41 @@ static inline void gpio_set_value(unsign
WARN_ON(1);
}
+static inline
+struct gpio_block *gpio_block_create(unsigned *gpios, size_t size,
+ const char *name)
+{
+ WARN_ON(1);
+ return NULL;
+}
+
+static inline void gpio_block_free(struct gpio_block *block)
+{
+ WARN_ON(1);
+}
+
+static inline unsigned long gpio_block_get(const struct gpio_block *block)
+{
+ WARN_ON(1);
+ return 0;
+}
+
+static inline void gpio_block_set(struct gpio_block *block, unsigned long value)
+{
+ WARN_ON(1);
+}
+
+static inline int gpio_block_register(struct gpio_block *block)
+{
+ WARN_ON(1);
+ return 0;
+}
+
+static inline void gpio_block_unregister(struct gpio_block *block)
+{
+ WARN_ON(1);
+}
+
static inline int gpio_cansleep(unsigned gpio)
{
/* GPIO can never have been requested or set as {in,out}put */
^ permalink raw reply
* [PATCH RFC 02/15 v5] gpio: Add sysfs support to block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds sysfs support to the block GPIO API.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
Documentation/ABI/testing/sysfs-gpio | 6
drivers/gpio/gpiolib.c | 214 +++++++++++++++++++++++++++++++++++
include/asm-generic/gpio.h | 11 +
include/linux/gpio.h | 13 ++
4 files changed, 243 insertions(+), 1 deletion(-)
--- linux-2.6.orig/Documentation/ABI/testing/sysfs-gpio
+++ linux-2.6/Documentation/ABI/testing/sysfs-gpio
@@ -24,4 +24,8 @@ Description:
/base ... (r/o) same as N
/label ... (r/o) descriptive, not necessarily unique
/ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1)
-
+ /blockN ... for each GPIO block #N
+ /ngpio ... (r/o) number of GPIOs in this group
+ /exported ... sysfs export state of this group (0, 1)
+ /value ... current value as 32 or 64 bit integer in decimal
+ (only available if /exported is 1)
--- linux-2.6.orig/drivers/gpio/gpiolib.c
+++ linux-2.6/drivers/gpio/gpiolib.c
@@ -972,6 +972,214 @@ static void gpiochip_unexport(struct gpi
chip->label, status);
}
+static ssize_t gpio_block_ngpio_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const struct gpio_block *block = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", block->ngpio);
+}
+
+static ssize_t gpio_block_value_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const struct gpio_block *block = dev_get_drvdata(dev);
+
+ return sprintf(buf, sizeof(unsigned long) == 4 ? "0x%08lx\n" :
+ "0x%016lx\n", gpio_block_get(block));
+}
+
+static bool gpio_block_is_output(struct gpio_block *block)
+{
+ int i;
+
+ for (i = 0; i < block->ngpio; i++)
+ if (!test_bit(FLAG_IS_OUT, &gpio_desc[block->gpio[i]].flags))
+ return false;
+ return true;
+}
+
+static ssize_t gpio_block_value_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t status;
+ struct gpio_block *block = dev_get_drvdata(dev);
+ unsigned long value;
+
+ status = kstrtoul(buf, 0, &value);
+ if (status == 0) {
+ mutex_lock(&sysfs_lock);
+ if (gpio_block_is_output(block)) {
+ gpio_block_set(block, value);
+ status = size;
+ } else {
+ status = -EPERM;
+ }
+ mutex_unlock(&sysfs_lock);
+ }
+ return status;
+}
+
+static struct device_attribute
+dev_attr_block_value = __ATTR(value, S_IWUSR | S_IRUGO, gpio_block_value_show,
+ gpio_block_value_store);
+
+static struct class gpio_block_class;
+
+static int gpio_block_value_is_exported(struct gpio_block *block)
+{
+ struct device *dev;
+ struct sysfs_dirent *sd = NULL;
+
+ mutex_lock(&sysfs_lock);
+ dev = class_find_device(&gpio_block_class, NULL, block, match_export);
+ if (!dev)
+ goto out;
+
+ sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value");
+
+out:
+ mutex_unlock(&sysfs_lock);
+ return !!sd;
+}
+
+static ssize_t gpio_block_exported_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct gpio_block *block = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", gpio_block_value_is_exported(block));
+}
+
+static int gpio_block_value_export(struct gpio_block *block)
+{
+ struct device *dev;
+ int status;
+ int i;
+
+ mutex_lock(&sysfs_lock);
+
+ for (i = 0; i < block->ngpio; i++) {
+ status = gpio_request(block->gpio[i], "sysfs");
+ if (status)
+ goto out;
+ }
+
+ dev = class_find_device(&gpio_block_class, NULL, block, match_export);
+ if (!dev) {
+ status = -ENODEV;
+ goto out;
+ }
+
+ status = device_create_file(dev, &dev_attr_block_value);
+ if (status)
+ goto out;
+
+ mutex_unlock(&sysfs_lock);
+ return 0;
+
+out:
+ while (--i >= 0)
+ gpio_free(block->gpio[i]);
+
+ mutex_unlock(&sysfs_lock);
+ return status;
+}
+
+static int gpio_block_value_unexport(struct gpio_block *block)
+{
+ struct device *dev;
+ int i;
+
+ dev = class_find_device(&gpio_block_class, NULL, block, match_export);
+ if (!dev)
+ return -ENODEV;
+
+ for (i = 0; i < block->ngpio; i++)
+ gpio_free(block->gpio[i]);
+
+ device_remove_file(dev, &dev_attr_block_value);
+
+ return 0;
+}
+
+static ssize_t gpio_block_exported_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ long value;
+ int status;
+ struct gpio_block *block = dev_get_drvdata(dev);
+ int exported = gpio_block_value_is_exported(block);
+
+ status = kstrtoul(buf, 0, &value);
+ if (status < 0)
+ goto err;
+
+ if (value != exported) {
+ if (value)
+ status = gpio_block_value_export(block);
+ else
+ status = gpio_block_value_unexport(block);
+ if (!status)
+ status = size;
+ } else {
+ status = size;
+ }
+err:
+ return status;
+}
+
+static struct device_attribute gpio_block_attrs[] = {
+ __ATTR(exported, S_IWUSR | S_IRUGO, gpio_block_exported_show,
+ gpio_block_exported_store),
+ __ATTR(ngpio, S_IRUGO, gpio_block_ngpio_show, NULL),
+ __ATTR_NULL,
+};
+
+static struct class gpio_block_class = {
+ .name = "gpioblock",
+ .owner = THIS_MODULE,
+
+ .dev_attrs = gpio_block_attrs,
+};
+
+int gpio_block_export(struct gpio_block *block)
+{
+ int status = 0;
+ struct device *dev;
+
+ /* can't export until sysfs is available ... */
+ if (!gpio_block_class.p) {
+ pr_debug("%s: called too early!\n", __func__);
+ return -ENOENT;
+ }
+
+ mutex_lock(&sysfs_lock);
+ dev = device_create(&gpio_block_class, NULL, MKDEV(0, 0), block,
+ block->name);
+ if (IS_ERR(dev))
+ status = PTR_ERR(dev);
+ mutex_unlock(&sysfs_lock);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpio_block_export);
+
+void gpio_block_unexport(struct gpio_block *block)
+{
+ struct device *dev;
+
+ mutex_lock(&sysfs_lock);
+ dev = class_find_device(&gpio_block_class, NULL, block, match_export);
+ if (dev)
+ device_unregister(dev);
+ mutex_unlock(&sysfs_lock);
+}
+EXPORT_SYMBOL_GPL(gpio_block_unexport);
+
static int __init gpiolib_sysfs_init(void)
{
int status;
@@ -982,6 +1190,10 @@ static int __init gpiolib_sysfs_init(voi
if (status < 0)
return status;
+ status = class_register(&gpio_block_class);
+ if (status < 0)
+ return status;
+
/* Scan and register the gpio_chips which registered very
* early (e.g. before the class_register above was called).
*
@@ -1876,6 +2088,7 @@ int gpio_block_register(struct gpio_bloc
return -EBUSY;
list_add(&block->list, &gpio_block_list);
+ gpio_block_export(block);
return 0;
}
@@ -1888,6 +2101,7 @@ void gpio_block_unregister(struct gpio_b
list_for_each_entry(i, &gpio_block_list, list)
if (i == block) {
list_del(&i->list);
+ gpio_block_unexport(block);
break;
}
}
--- linux-2.6.orig/include/asm-generic/gpio.h
+++ linux-2.6/include/asm-generic/gpio.h
@@ -211,6 +211,8 @@ extern int gpio_export_link(struct devic
unsigned gpio);
extern int gpio_sysfs_set_active_low(unsigned gpio, int value);
extern void gpio_unexport(unsigned gpio);
+extern int gpio_block_export(struct gpio_block *block);
+extern void gpio_block_unexport(struct gpio_block *block);
#endif /* CONFIG_GPIO_SYSFS */
@@ -270,6 +272,15 @@ static inline int gpio_sysfs_set_active_
static inline void gpio_unexport(unsigned gpio)
{
}
+
+static inline int gpio_block_export(struct gpio_block *block)
+{
+ return -ENOSYS;
+}
+
+static inline void gpio_block_unexport(struct gpio_block *block)
+{
+}
#endif /* CONFIG_GPIO_SYSFS */
#endif /* _ASM_GENERIC_GPIO_H */
--- linux-2.6.orig/include/linux/gpio.h
+++ linux-2.6/include/linux/gpio.h
@@ -291,6 +291,19 @@ static inline void gpio_unexport(unsigne
WARN_ON(1);
}
+static inline int gpio_block_export(struct gpio_block *block)
+{
+ /* GPIO block can never have been requested or set as {in,out}put */
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+static inline void gpio_block_unexport(struct gpio_block *block)
+{
+ /* GPIO block can never have been exported */
+ WARN_ON(1);
+}
+
static inline int gpio_to_irq(unsigned gpio)
{
/* GPIO can never have been requested or set as input */
^ permalink raw reply
* [PATCH RFC 03/15 v5] gpiolib: Fix default attributes for class
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
There is a race condition between creating a gpio or gpiochip device and adding
default attribues. This patch fixes this by defining the default attributes as
dev_attrs of the class. For this, it was necessary to create a separate
gpiochip_class besides gpio_class.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpiolib.c | 79 +++++++++++++++++++++----------------------------
1 file changed, 34 insertions(+), 45 deletions(-)
--- linux-2.6.orig/drivers/gpio/gpiolib.c
+++ linux-2.6/drivers/gpio/gpiolib.c
@@ -321,9 +321,6 @@ static ssize_t gpio_value_store(struct d
return status;
}
-static const DEVICE_ATTR(value, 0644,
- gpio_value_show, gpio_value_store);
-
static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
{
struct sysfs_dirent *value_sd = priv;
@@ -544,19 +541,6 @@ static ssize_t gpio_active_low_store(str
return status ? : size;
}
-static const DEVICE_ATTR(active_low, 0644,
- gpio_active_low_show, gpio_active_low_store);
-
-static const struct attribute *gpio_attrs[] = {
- &dev_attr_value.attr,
- &dev_attr_active_low.attr,
- NULL,
-};
-
-static const struct attribute_group gpio_attr_group = {
- .attrs = (struct attribute **) gpio_attrs,
-};
-
/*
* /sys/class/gpio/gpiochipN/
* /base ... matching gpio_chip.base (N)
@@ -571,7 +555,6 @@ static ssize_t chip_base_show(struct dev
return sprintf(buf, "%d\n", chip->base);
}
-static DEVICE_ATTR(base, 0444, chip_base_show, NULL);
static ssize_t chip_label_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -580,7 +563,6 @@ static ssize_t chip_label_show(struct de
return sprintf(buf, "%s\n", chip->label ? : "");
}
-static DEVICE_ATTR(label, 0444, chip_label_show, NULL);
static ssize_t chip_ngpio_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -589,18 +571,6 @@ static ssize_t chip_ngpio_show(struct de
return sprintf(buf, "%u\n", chip->ngpio);
}
-static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
-
-static const struct attribute *gpiochip_attrs[] = {
- &dev_attr_base.attr,
- &dev_attr_label.attr,
- &dev_attr_ngpio.attr,
- NULL,
-};
-
-static const struct attribute_group gpiochip_attr_group = {
- .attrs = (struct attribute **) gpiochip_attrs,
-};
/*
* /sys/class/gpio/export ... write-only
@@ -677,11 +647,32 @@ static struct class_attribute gpio_class
__ATTR_NULL,
};
+static struct device_attribute gpio_attrs[] = {
+ __ATTR(active_low, 0644, gpio_active_low_show, gpio_active_low_store),
+ __ATTR(value, 0644, gpio_value_show, gpio_value_store),
+ __ATTR_NULL,
+};
+
static struct class gpio_class = {
.name = "gpio",
.owner = THIS_MODULE,
- .class_attrs = gpio_class_attrs,
+ .class_attrs = gpio_class_attrs,
+ .dev_attrs = gpio_attrs,
+};
+
+static struct device_attribute gpiochip_attrs[] = {
+ __ATTR(label, 0444, chip_label_show, NULL),
+ __ATTR(base, 0444, chip_base_show, NULL),
+ __ATTR(ngpio, 0444, chip_ngpio_show, NULL),
+ __ATTR_NULL,
+};
+
+static struct class gpiochip_class = {
+ .name = "gpiochip",
+ .owner = THIS_MODULE,
+
+ .dev_attrs = gpiochip_attrs,
};
@@ -738,10 +729,7 @@ int gpio_export(unsigned gpio, bool dire
dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
desc, ioname ? ioname : "gpio%u", gpio);
if (!IS_ERR(dev)) {
- status = sysfs_create_group(&dev->kobj,
- &gpio_attr_group);
-
- if (!status && direction_may_change)
+ if (direction_may_change)
status = device_create_file(dev,
&dev_attr_direction);
@@ -911,25 +899,22 @@ EXPORT_SYMBOL_GPL(gpio_unexport);
static int gpiochip_export(struct gpio_chip *chip)
{
- int status;
+ int status = 0;
struct device *dev;
/* Many systems register gpio chips for SOC support very early,
* before driver model support is available. In those cases we
* export this later, in gpiolib_sysfs_init() ... here we just
- * verify that _some_ field of gpio_class got initialized.
+ * verify that _some_ field of gpiochip_class got initialized.
*/
- if (!gpio_class.p)
+ if (!gpiochip_class.p)
return 0;
/* use chip->base for the ID; it's already known to be unique */
mutex_lock(&sysfs_lock);
- dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,
- "gpiochip%d", chip->base);
- if (!IS_ERR(dev)) {
- status = sysfs_create_group(&dev->kobj,
- &gpiochip_attr_group);
- } else
+ dev = device_create(&gpiochip_class, chip->dev, MKDEV(0, 0), chip,
+ "gpiochip%d", chip->base);
+ if (IS_ERR(dev))
status = PTR_ERR(dev);
chip->exported = (status == 0);
mutex_unlock(&sysfs_lock);
@@ -957,7 +942,7 @@ static void gpiochip_unexport(struct gpi
struct device *dev;
mutex_lock(&sysfs_lock);
- dev = class_find_device(&gpio_class, NULL, chip, match_export);
+ dev = class_find_device(&gpiochip_class, NULL, chip, match_export);
if (dev) {
put_device(dev);
device_unregister(dev);
@@ -1190,6 +1175,10 @@ static int __init gpiolib_sysfs_init(voi
if (status < 0)
return status;
+ status = class_register(&gpiochip_class);
+ if (status < 0)
+ return status;
+
status = class_register(&gpio_block_class);
if (status < 0)
return status;
^ permalink raw reply
* [PATCH RFC 04/15 v5] gpio: Add device tree support to block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds device tree support to the block GPIO API.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
Documentation/devicetree/bindings/gpio/gpio-block.txt | 36 +++++++
drivers/gpio/Makefile | 1
drivers/gpio/gpioblock-of.c | 84 ++++++++++++++++++
3 files changed, 121 insertions(+)
--- /dev/null
+++ linux-2.6/Documentation/devicetree/bindings/gpio/gpio-block.txt
@@ -0,0 +1,36 @@
+Block GPIO definition
+=====================
+
+This binding specifies arbitrary blocks of gpios, combining gpios from one or
+more GPIO controllers together, to form a word for r/w access.
+
+Required property:
+- compatible: must be "linux,gpio-block"
+
+Required subnodes:
+- the name will be the registered name of the block
+- property "gpios" is a list of gpios for the respective block
+
+Example:
+
+ blockgpio {
+ compatible = "linux,gpio-block";
+
+ block0 {
+ gpios = <&gpio 3 0 0>,
+ <&gpio 3 1 0>;
+ };
+ block1 {
+ gpios = <&gpio 4 1 0>,
+ <&gpio 4 3 0>,
+ <&gpio 4 2 0>,
+ <&gpio 4 4 0>,
+ <&gpio 4 5 0>,
+ <&gpio 4 6 0>,
+ <&gpio 4 7 0>,
+ <&gpio 4 8 0>,
+ <&gpio 4 9 0>,
+ <&gpio 4 10 0>,
+ <&gpio 4 19 0>;
+ };
+ };
--- linux-2.6.orig/drivers/gpio/Makefile
+++ linux-2.6/drivers/gpio/Makefile
@@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
+obj-$(CONFIG_OF_GPIO) += gpioblock-of.o
# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
--- /dev/null
+++ linux-2.6/drivers/gpio/gpioblock-of.c
@@ -0,0 +1,84 @@
+/*
+ * OF implementation for Block GPIO
+ *
+ * Copyright (C) 2012 Roland Stigge <stigge@antcom.de>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+static int __devinit gpioblock_of_probe(struct platform_device *pdev)
+{
+ struct device_node *block;
+ unsigned *gpios;
+ int ngpio;
+ int ret;
+ struct gpio_block *gb;
+
+ for_each_available_child_of_node(pdev->dev.of_node, block) {
+ int i;
+
+ ngpio = of_gpio_count(block);
+ gpios = kzalloc(ngpio * sizeof(*gpios), GFP_KERNEL);
+ if (!gpios)
+ return -ENOMEM;
+ for (i = 0; i < ngpio; i++) {
+ ret = of_get_gpio(block, i);
+ if (ret < 0)
+ return ret; /* expect -EPROBE_DEFER */
+ gpios[i] = ret;
+ }
+ gb = gpio_block_create(gpios, ngpio, block->name);
+ if (IS_ERR(gb)) {
+ dev_err(&pdev->dev,
+ "Error creating GPIO block from device tree\n");
+ return PTR_ERR(gb);
+ }
+ ret = gpio_block_register(gb);
+ if (ret < 0) {
+ gpio_block_free(gb);
+ return ret;
+ }
+ kfree(gpios);
+ dev_info(&pdev->dev, "Registered gpio block %s: %d gpios\n",
+ block->name, ngpio);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id gpioblock_of_match[] __devinitdata = {
+ { .compatible = "linux,gpio-block", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, gpioblock_of_match);
+#endif
+
+static struct platform_driver gpioblock_of_driver = {
+ .driver = {
+ .name = "gpio-block",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(gpioblock_of_match),
+
+ },
+ .probe = gpioblock_of_probe,
+};
+
+module_platform_driver(gpioblock_of_driver);
+
+MODULE_DESCRIPTION("GPIO Block driver");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpioblock-of");
^ permalink raw reply
* [PATCH RFC 05/15 v5] gpio-max730x: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the MAX730x driver.
Due to hardware constraints in this chip, simultaneous access to GPIO lines can
only be done in groups of 8: GPIOs 0-7, 8-15, 16-23, 24-27. However, setting
and clearing will be done at once.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-max730x.c | 61 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-max730x.c
+++ linux-2.6/drivers/gpio/gpio-max730x.c
@@ -146,6 +146,44 @@ static int max7301_get(struct gpio_chip
return level;
}
+static unsigned long max7301_get_block(struct gpio_chip *chip,
+ unsigned long mask)
+{
+ struct max7301 *ts = container_of(chip, struct max7301, chip);
+ int i, j;
+ unsigned long result = 0;
+
+ for (i = 0; i < 4; i++) {
+ if ((mask >> (i * 8)) & 0xFF) { /* i/o only if necessary */
+ u8 in_level = ts->read(ts->dev, 0x44 + i * 8);
+ u8 in_mask = 0;
+ u8 out_level = (ts->out_level >> (i * 8 + 4)) & 0xFF;
+ u8 out_mask = 0;
+
+ for (j = 0; j < 8; j++) {
+ int offset = 4 + i * 8 + j;
+ int config = (ts->port_config[offset >> 2] >>
+ ((offset & 3) << 1)) &
+ PIN_CONFIG_MASK;
+
+ switch (config) {
+ case PIN_CONFIG_OUT:
+ out_mask |= BIT(j);
+ break;
+ case PIN_CONFIG_IN_WO_PULLUP:
+ case PIN_CONFIG_IN_PULLUP:
+ in_mask |= BIT(j);
+ }
+ }
+
+ result |= ((unsigned long)(in_level & in_mask) |
+ (out_level & out_mask)) << (i * 8);
+ }
+ }
+
+ return result & mask;
+}
+
static void max7301_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct max7301 *ts = container_of(chip, struct max7301, chip);
@@ -160,6 +198,27 @@ static void max7301_set(struct gpio_chip
mutex_unlock(&ts->lock);
}
+static void max7301_set_block(struct gpio_chip *chip, unsigned long mask,
+ unsigned long values)
+{
+ struct max7301 *ts = container_of(chip, struct max7301, chip);
+ unsigned long changes;
+ int i;
+
+ mutex_lock(&ts->lock);
+
+ changes = (ts->out_level ^ (values << 4)) & (mask << 4);
+ ts->out_level ^= changes;
+
+ for (i = 0; i < 4; i++) {
+ if ((changes >> (i * 8 + 4)) & 0xFF) /* i/o only on change */
+ ts->write(ts->dev, 0x44 + i * 8,
+ (ts->out_level >> (i * 8 + 4)) & 0xFF);
+ }
+
+ mutex_unlock(&ts->lock);
+}
+
int __devinit __max730x_probe(struct max7301 *ts)
{
struct device *dev = ts->dev;
@@ -183,8 +242,10 @@ int __devinit __max730x_probe(struct max
ts->chip.direction_input = max7301_direction_input;
ts->chip.get = max7301_get;
+ ts->chip.get_block = max7301_get_block;
ts->chip.direction_output = max7301_direction_output;
ts->chip.set = max7301_set;
+ ts->chip.set_block = max7301_set_block;
ts->chip.base = pdata->base;
ts->chip.ngpio = PIN_NUMBER;
^ permalink raw reply
* [PATCH RFC 06/15 v5] gpio-lpc32xx: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the LPC32xx driver.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-lpc32xx.c | 82 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-lpc32xx.c
+++ linux-2.6/drivers/gpio/gpio-lpc32xx.c
@@ -297,6 +297,22 @@ static int lpc32xx_gpio_get_value_p3(str
return __get_gpio_state_p3(group, pin);
}
+static unsigned long lpc32xx_gpio_get_block_p3(struct gpio_chip *chip,
+ unsigned long mask)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ u32 bits = __raw_readl(group->gpio_grp->inp_state);
+
+ /* In P3_INP_STATE, the 6 GPIOs are scattered over the register,
+ * rearranging to bits 0-5
+ */
+ bits >>= 10;
+ bits &= 0x401F;
+ bits |= (bits & 0x4000) >> 9;
+
+ return bits & mask & 0x3F;
+}
+
static int lpc32xx_gpi_get_value(struct gpio_chip *chip, unsigned pin)
{
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
@@ -304,6 +320,15 @@ static int lpc32xx_gpi_get_value(struct
return __get_gpi_state_p3(group, pin);
}
+static unsigned long lpc32xx_gpi_get_block(struct gpio_chip *chip,
+ unsigned long mask)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ u32 bits = __raw_readl(group->gpio_grp->inp_state);
+
+ return bits & mask;
+}
+
static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
int value)
{
@@ -351,6 +376,27 @@ static void lpc32xx_gpio_set_value_p3(st
__set_gpio_level_p3(group, pin, value);
}
+static void lpc32xx_gpio_set_block_p3(struct gpio_chip *chip,
+ unsigned long mask,
+ unsigned long values)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ u32 set_bits = values & mask;
+ u32 clr_bits = ~values & mask;
+
+ /* States of GPIO 0-5 start at bit 25 */
+ set_bits <<= 25;
+ clr_bits <<= 25;
+
+ /* Note: On LPC32xx, GPOs can only be set at once or cleared at once,
+ * but not set and cleared@once
+ */
+ if (set_bits)
+ __raw_writel(set_bits, group->gpio_grp->outp_set);
+ if (clr_bits)
+ __raw_writel(clr_bits, group->gpio_grp->outp_clr);
+}
+
static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin,
int value)
{
@@ -366,6 +412,31 @@ static int lpc32xx_gpo_get_value(struct
return __get_gpo_state_p3(group, pin);
}
+static void lpc32xx_gpo_set_block(struct gpio_chip *chip, unsigned long mask,
+ unsigned long values)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ u32 set_bits = values & mask;
+ u32 clr_bits = ~values & mask;
+
+ /* Note: On LPC32xx, GPOs can only be set at once or cleared at once,
+ * but not set and cleared at once
+ */
+ if (set_bits)
+ __raw_writel(set_bits, group->gpio_grp->outp_set);
+ if (clr_bits)
+ __raw_writel(clr_bits, group->gpio_grp->outp_clr);
+}
+
+static unsigned long lpc32xx_gpo_get_block(struct gpio_chip *chip,
+ unsigned long mask)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+ u32 bits = __raw_readl(group->gpio_grp->outp_state);
+
+ return bits & mask;
+}
+
static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
{
if (pin < chip->ngpio)
@@ -440,8 +511,10 @@ static struct lpc32xx_gpio_chip lpc32xx_
.label = "gpio_p0",
.direction_input = lpc32xx_gpio_dir_input_p012,
.get = lpc32xx_gpio_get_value_p012,
+ .get_block = lpc32xx_gpi_get_block,
.direction_output = lpc32xx_gpio_dir_output_p012,
.set = lpc32xx_gpio_set_value_p012,
+ .set_block = lpc32xx_gpo_set_block,
.request = lpc32xx_gpio_request,
.to_irq = lpc32xx_gpio_to_irq_p01,
.base = LPC32XX_GPIO_P0_GRP,
@@ -456,8 +529,10 @@ static struct lpc32xx_gpio_chip lpc32xx_
.label = "gpio_p1",
.direction_input = lpc32xx_gpio_dir_input_p012,
.get = lpc32xx_gpio_get_value_p012,
+ .get_block = lpc32xx_gpi_get_block,
.direction_output = lpc32xx_gpio_dir_output_p012,
.set = lpc32xx_gpio_set_value_p012,
+ .set_block = lpc32xx_gpo_set_block,
.request = lpc32xx_gpio_request,
.to_irq = lpc32xx_gpio_to_irq_p01,
.base = LPC32XX_GPIO_P1_GRP,
@@ -472,8 +547,10 @@ static struct lpc32xx_gpio_chip lpc32xx_
.label = "gpio_p2",
.direction_input = lpc32xx_gpio_dir_input_p012,
.get = lpc32xx_gpio_get_value_p012,
+ .get_block = lpc32xx_gpi_get_block,
.direction_output = lpc32xx_gpio_dir_output_p012,
.set = lpc32xx_gpio_set_value_p012,
+ .set_block = lpc32xx_gpo_set_block,
.request = lpc32xx_gpio_request,
.base = LPC32XX_GPIO_P2_GRP,
.ngpio = LPC32XX_GPIO_P2_MAX,
@@ -487,8 +564,10 @@ static struct lpc32xx_gpio_chip lpc32xx_
.label = "gpio_p3",
.direction_input = lpc32xx_gpio_dir_input_p3,
.get = lpc32xx_gpio_get_value_p3,
+ .get_block = lpc32xx_gpio_get_block_p3,
.direction_output = lpc32xx_gpio_dir_output_p3,
.set = lpc32xx_gpio_set_value_p3,
+ .set_block = lpc32xx_gpio_set_block_p3,
.request = lpc32xx_gpio_request,
.to_irq = lpc32xx_gpio_to_irq_gpio_p3,
.base = LPC32XX_GPIO_P3_GRP,
@@ -503,6 +582,7 @@ static struct lpc32xx_gpio_chip lpc32xx_
.label = "gpi_p3",
.direction_input = lpc32xx_gpio_dir_in_always,
.get = lpc32xx_gpi_get_value,
+ .get_block = lpc32xx_gpi_get_block,
.request = lpc32xx_gpio_request,
.to_irq = lpc32xx_gpio_to_irq_gpi_p3,
.base = LPC32XX_GPI_P3_GRP,
@@ -517,7 +597,9 @@ static struct lpc32xx_gpio_chip lpc32xx_
.label = "gpo_p3",
.direction_output = lpc32xx_gpio_dir_out_always,
.set = lpc32xx_gpo_set_value,
+ .set_block = lpc32xx_gpo_set_block,
.get = lpc32xx_gpo_get_value,
+ .get_block = lpc32xx_gpo_get_block,
.request = lpc32xx_gpio_request,
.base = LPC32XX_GPO_P3_GRP,
.ngpio = LPC32XX_GPO_P3_MAX,
^ permalink raw reply
* [PATCH RFC 07/15 v5] gpio-generic: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the gpio-generic driver.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-generic.c | 56 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-generic.c
+++ linux-2.6/drivers/gpio/gpio-generic.c
@@ -122,6 +122,13 @@ static int bgpio_get(struct gpio_chip *g
return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio);
}
+static unsigned long bgpio_get_block(struct gpio_chip *gc, unsigned long mask)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+ return bgc->read_reg(bgc->reg_dat) & mask;
+}
+
static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
@@ -170,6 +177,51 @@ static void bgpio_set_set(struct gpio_ch
spin_unlock_irqrestore(&bgc->lock, flags);
}
+static void bgpio_set_block(struct gpio_chip *gc, unsigned long mask,
+ unsigned long values)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+
+ bgc->data &= ~mask;
+ bgc->data |= values & mask;
+
+ bgc->write_reg(bgc->reg_dat, bgc->data);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static void bgpio_set_with_clear_block(struct gpio_chip *gc, unsigned long mask,
+ unsigned long values)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long set_bits = values & mask;
+ unsigned long clr_bits = ~values & mask;
+
+ if (set_bits)
+ bgc->write_reg(bgc->reg_set, set_bits);
+ if (clr_bits)
+ bgc->write_reg(bgc->reg_set, clr_bits);
+}
+
+static void bgpio_set_set_block(struct gpio_chip *gc, unsigned long mask,
+ unsigned long values)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+
+ bgc->data &= ~mask;
+ bgc->data |= values & mask;
+
+ bgc->write_reg(bgc->reg_set, bgc->data);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
return 0;
@@ -317,14 +369,18 @@ static int bgpio_setup_io(struct bgpio_c
bgc->reg_set = set;
bgc->reg_clr = clr;
bgc->gc.set = bgpio_set_with_clear;
+ bgc->gc.set_block = bgpio_set_with_clear_block;
} else if (set && !clr) {
bgc->reg_set = set;
bgc->gc.set = bgpio_set_set;
+ bgc->gc.set_block = bgpio_set_set_block;
} else {
bgc->gc.set = bgpio_set;
+ bgc->gc.set_block = bgpio_set_block;
}
bgc->gc.get = bgpio_get;
+ bgc->gc.get_block = bgpio_get_block;
return 0;
}
^ permalink raw reply
* [PATCH RFC 08/15 v5] gpio-pca953x: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the gpio-pca953x driver.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-pca953x.c | 64 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-pca953x.c
+++ linux-2.6/drivers/gpio/gpio-pca953x.c
@@ -300,6 +300,68 @@ exit:
mutex_unlock(&chip->i2c_lock);
}
+static unsigned long pca953x_gpio_get_block(struct gpio_chip *gc,
+ unsigned long mask)
+{
+ struct pca953x_chip *chip;
+ u32 reg_val;
+ int ret, offset = 0;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+ mutex_lock(&chip->i2c_lock);
+ switch (chip->chip_type) {
+ case PCA953X_TYPE:
+ offset = PCA953X_INPUT;
+ break;
+ case PCA957X_TYPE:
+ offset = PCA957X_IN;
+ break;
+ }
+ ret = pca953x_read_reg(chip, offset, ®_val);
+ mutex_unlock(&chip->i2c_lock);
+ if (ret < 0) {
+ /* NOTE: diagnostic already emitted; that's all we should
+ * do unless gpio_*_value_cansleep() calls become different
+ * from their nonsleeping siblings (and report faults).
+ */
+ return 0;
+ }
+
+ return reg_val & mask;
+}
+
+static void pca953x_gpio_set_block(struct gpio_chip *gc, unsigned long mask,
+ unsigned long values)
+{
+ struct pca953x_chip *chip;
+ u32 reg_val;
+ int ret, offset = 0;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+ mutex_lock(&chip->i2c_lock);
+
+ reg_val = chip->reg_output & ~mask;
+ reg_val |= values & mask;
+
+ switch (chip->chip_type) {
+ case PCA953X_TYPE:
+ offset = PCA953X_OUTPUT;
+ break;
+ case PCA957X_TYPE:
+ offset = PCA957X_OUT;
+ break;
+ }
+ ret = pca953x_write_reg(chip, offset, reg_val);
+ if (ret)
+ goto exit;
+
+ chip->reg_output = reg_val;
+exit:
+ mutex_unlock(&chip->i2c_lock);
+}
+
static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
{
struct gpio_chip *gc;
@@ -310,6 +372,8 @@ static void pca953x_setup_gpio(struct pc
gc->direction_output = pca953x_gpio_direction_output;
gc->get = pca953x_gpio_get_value;
gc->set = pca953x_gpio_set_value;
+ gc->get_block = pca953x_gpio_get_block;
+ gc->set_block = pca953x_gpio_set_block;
gc->can_sleep = 1;
gc->base = chip->gpio_start;
^ permalink raw reply
* [PATCH RFC 09/15 v5] gpio-em: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the gpio-em driver.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-em.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-em.c
+++ linux-2.6/drivers/gpio/gpio-em.c
@@ -203,6 +203,27 @@ static void em_gio_set(struct gpio_chip
__em_gio_set(chip, GIO_OH, offset - 16, value);
}
+static unsigned long em_gio_get_block(struct gpio_chip *chip,
+ unsigned long mask)
+{
+ return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & mask);
+}
+
+static void em_gio_set_block(struct gpio_chip *chip, unsigned long mask,
+ unsigned long values)
+{
+ unsigned long mask_ol = mask & 0xFFFF;
+ unsigned long mask_oh = mask >> 16;
+
+ unsigned long values_ol = values & mask_ol;
+ unsigned long values_oh = (values >> 16) & mask_oh;
+
+ em_gio_write(gpio_to_priv(chip), GIO_OL,
+ mask_ol << 16 | values_ol);
+ em_gio_write(gpio_to_priv(chip), GIO_OH,
+ mask_oh << 16 | values_oh);
+}
+
static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
@@ -317,8 +338,10 @@ static int __devinit em_gio_probe(struct
gpio_chip = &p->gpio_chip;
gpio_chip->direction_input = em_gio_direction_input;
gpio_chip->get = em_gio_get;
+ gpio_chip->get_block = em_gio_get_block;
gpio_chip->direction_output = em_gio_direction_output;
gpio_chip->set = em_gio_set;
+ gpio_chip->set_block = em_gio_set_block;
gpio_chip->to_irq = em_gio_to_irq;
gpio_chip->label = name;
gpio_chip->owner = THIS_MODULE;
^ permalink raw reply
* [PATCH RFC 10/15 v5] gpio-pl061: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the gpio-pl061 driver.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-pl061.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-pl061.c
+++ linux-2.6/drivers/gpio/gpio-pl061.c
@@ -123,6 +123,21 @@ static void pl061_set_value(struct gpio_
writeb(!!value << offset, chip->base + (1 << (offset + 2)));
}
+static unsigned long pl061_get_block(struct gpio_chip *gc, unsigned long mask)
+{
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+
+ return !!readb(chip->base + (mask << 2));
+}
+
+static void pl061_set_block(struct gpio_chip *gc, unsigned long mask,
+ unsigned long values)
+{
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+
+ writeb(values & mask, chip->base + (mask << 2));
+}
+
static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
@@ -256,6 +271,8 @@ static int pl061_probe(struct amba_devic
chip->gc.direction_output = pl061_direction_output;
chip->gc.get = pl061_get_value;
chip->gc.set = pl061_set_value;
+ chip->gc.get_block = pl061_get_block;
+ chip->gc.set_block = pl061_set_block;
chip->gc.to_irq = pl061_to_irq;
chip->gc.ngpio = PL061_GPIO_NR;
chip->gc.label = dev_name(&dev->dev);
^ permalink raw reply
* [PATCH RFC 11/15 v5] gpio-max732x: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the gpio-max732x driver.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-max732x.c | 59 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-max732x.c
+++ linux-2.6/drivers/gpio/gpio-max732x.c
@@ -219,6 +219,63 @@ out:
mutex_unlock(&chip->lock);
}
+static unsigned long max732x_gpio_get_block(struct gpio_chip *gc,
+ unsigned long mask)
+{
+ struct max732x_chip *chip;
+ uint8_t lo = 0;
+ uint8_t hi = 0;
+ int ret;
+
+ chip = container_of(gc, struct max732x_chip, gpio_chip);
+
+ if (mask & 0xFF) {
+ ret = max732x_readb(chip, is_group_a(chip, 0), &lo);
+ if (ret < 0)
+ return 0;
+ }
+ if (mask & 0xFF00) {
+ ret = max732x_readb(chip, is_group_a(chip, 8), &hi);
+ if (ret < 0)
+ return 0;
+ }
+
+ return (((unsigned long)hi << 8) | lo) & mask;
+}
+
+static void max732x_gpio_set_block(struct gpio_chip *gc, unsigned long mask,
+ unsigned long values)
+{
+ struct max732x_chip *chip;
+ uint8_t reg_out;
+ uint8_t lo_mask = mask & 0xFF;
+ uint8_t hi_mask = (mask >> 8) & 0xFF;
+ int ret;
+
+ chip = container_of(gc, struct max732x_chip, gpio_chip);
+
+ mutex_lock(&chip->lock);
+
+ if (lo_mask) {
+ reg_out = (chip->reg_out[0] & ~lo_mask) | (values & lo_mask);
+ ret = max732x_writeb(chip, is_group_a(chip, 0), reg_out);
+ if (ret < 0)
+ goto out;
+ chip->reg_out[0] = reg_out;
+ }
+ if (hi_mask) {
+ reg_out = (chip->reg_out[1] & ~hi_mask) |
+ ((values >> 8) & hi_mask);
+ ret = max732x_writeb(chip, is_group_a(chip, 8), reg_out);
+ if (ret < 0)
+ goto out;
+ chip->reg_out[1] = reg_out;
+ }
+
+out:
+ mutex_unlock(&chip->lock);
+}
+
static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{
struct max732x_chip *chip;
@@ -562,8 +619,10 @@ static int __devinit max732x_setup_gpio(
if (chip->dir_output) {
gc->direction_output = max732x_gpio_direction_output;
gc->set = max732x_gpio_set_value;
+ gc->set_block = max732x_gpio_set_block;
}
gc->get = max732x_gpio_get_value;
+ gc->get_block = max732x_gpio_get_block;
gc->can_sleep = 1;
gc->base = gpio_start;
^ permalink raw reply
* [PATCH RFC 12/15 v5] gpio-pcf857x: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the gpio-pcf857x driver.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-pcf857x.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-pcf857x.c
+++ linux-2.6/drivers/gpio/gpio-pcf857x.c
@@ -158,6 +158,28 @@ static void pcf857x_set(struct gpio_chip
pcf857x_output(chip, offset, value);
}
+static unsigned long pcf857x_get_block(struct gpio_chip *chip,
+ unsigned long mask)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ int value;
+
+ value = gpio->read(gpio->client);
+ return (value < 0) ? 0 : (value & mask);
+}
+
+static void pcf857x_set_block(struct gpio_chip *chip, unsigned long mask,
+ unsigned long values)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+
+ mutex_lock(&gpio->lock);
+ gpio->out &= ~mask;
+ gpio->out |= values & mask;
+ gpio->write(gpio->client, gpio->out);
+ mutex_unlock(&gpio->lock);
+}
+
/*-------------------------------------------------------------------------*/
static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -280,6 +302,8 @@ static int pcf857x_probe(struct i2c_clie
gpio->chip.owner = THIS_MODULE;
gpio->chip.get = pcf857x_get;
gpio->chip.set = pcf857x_set;
+ gpio->chip.get_block = pcf857x_get_block;
+ gpio->chip.set_block = pcf857x_set_block;
gpio->chip.direction_input = pcf857x_input;
gpio->chip.direction_output = pcf857x_output;
gpio->chip.ngpio = id->driver_data;
^ permalink raw reply
* [PATCH RFC 13/15 v5] gpio-xilinx: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the gpio-xilinx driver.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-xilinx.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-xilinx.c
+++ linux-2.6/drivers/gpio/gpio-xilinx.c
@@ -49,6 +49,21 @@ static int xgpio_get(struct gpio_chip *g
}
/**
+ * xgpio_get_block - Read a block of specified signals of the GPIO device.
+ * @gc: Pointer to gpio_chip device structure.
+ * @mask: Bit mask (bit 0 == 0th GPIO) for GPIOs to get
+ *
+ * This function reads a block of specified signal of the GPIO device, returned
+ * as a bit mask, each bit representing a GPIO
+ */
+static unsigned long xgpio_get_block(struct gpio_chip *gc, unsigned long mask)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+
+ return in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) & mask;
+}
+
+/**
* xgpio_set - Write the specified signal of the GPIO device.
* @gc: Pointer to gpio_chip device structure.
* @gpio: GPIO signal number.
@@ -77,6 +92,33 @@ static void xgpio_set(struct gpio_chip *
}
/**
+ * xgpio_set_block - Write a block of specified signals of the GPIO device.
+ * @gc: Pointer to gpio_chip device structure.
+ * @mask: Bit mask (bit 0 == 0th GPIO) for GPIOs to set
+ * @values: Bit mapped values
+ *
+ * This function writes the specified values in to the specified signals of the
+ * GPIO device.
+ */
+static void xgpio_set_block(struct gpio_chip *gc, unsigned long mask,
+ unsigned long values)
+{
+ unsigned long flags;
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct xgpio_instance *chip =
+ container_of(mm_gc, struct xgpio_instance, mmchip);
+
+ spin_lock_irqsave(&chip->gpio_lock, flags);
+
+ chip->gpio_state &= ~mask;
+ chip->gpio_state |= mask & values;
+
+ out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
+}
+
+/**
* xgpio_dir_in - Set the direction of the specified GPIO signal as input.
* @gc: Pointer to gpio_chip device structure.
* @gpio: GPIO signal number.
@@ -195,6 +237,8 @@ static int __devinit xgpio_of_probe(stru
chip->mmchip.gc.direction_output = xgpio_dir_out;
chip->mmchip.gc.get = xgpio_get;
chip->mmchip.gc.set = xgpio_set;
+ chip->mmchip.gc.get_block = xgpio_get_block;
+ chip->mmchip.gc.set_block = xgpio_set_block;
chip->mmchip.save_regs = xgpio_save_regs;
^ permalink raw reply
* [PATCH RFC 14/15 v5] gpio-vt8500: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the gpio-vt8500 driver.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-vt8500.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-vt8500.c
+++ linux-2.6/drivers/gpio/gpio-vt8500.c
@@ -209,6 +209,28 @@ static void vt8500_gpio_set_value(struct
writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out);
}
+static unsigned long vt8500_gpio_get_block(struct gpio_chip *chip,
+ unsigned long mask)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ return readl_relaxed(vt8500_chip->base + vt8500_chip->regs->data_in) &
+ mask;
+}
+
+static void vt8500_gpio_set_block(struct gpio_chip *chip, unsigned long mask,
+ unsigned long values)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ u32 val = readl_relaxed(vt8500_chip->base +
+ vt8500_chip->regs->data_out);
+ val &= ~mask;
+ val |= values & mask;
+
+ writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out);
+}
+
static int vt8500_of_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags)
{
@@ -251,6 +273,8 @@ static int vt8500_add_chips(struct platf
chip->direction_output = vt8500_gpio_direction_output;
chip->get = vt8500_gpio_get_value;
chip->set = vt8500_gpio_set_value;
+ chip->get_block = vt8500_gpio_get_block;
+ chip->set_block = vt8500_gpio_set_block;
chip->can_sleep = 0;
chip->base = pin_cnt;
chip->ngpio = data->banks[i].ngpio;
^ permalink raw reply
* [PATCH RFC 15/15 v5] gpio-ucb1400: Add block GPIO API
From: Roland Stigge @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477107-26512-1-git-send-email-stigge@antcom.de>
This patch adds block GPIO API support to the gpio-ucb1400 driver.
Signed-off-by: Roland Stigge <stigge@antcom.de>
---
drivers/gpio/gpio-ucb1400.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
--- linux-2.6.orig/drivers/gpio/gpio-ucb1400.c
+++ linux-2.6/drivers/gpio/gpio-ucb1400.c
@@ -45,6 +45,27 @@ static void ucb1400_gpio_set(struct gpio
ucb1400_gpio_set_value(gpio->ac97, off, val);
}
+static unsigned long ucb1400_gpio_get_block(struct gpio_chip *gc,
+ unsigned long mask)
+{
+ struct ucb1400_gpio *gpio;
+ gpio = container_of(gc, struct ucb1400_gpio, gc);
+ return ucb1400_reg_read(gpio->ac97, UCB_IO_DATA) & mask;
+}
+
+static void ucb1400_gpio_set_block(struct gpio_chip *gc, unsigned long mask,
+ unsigned long values)
+{
+ struct ucb1400_gpio *gpio;
+ u16 tmp;
+ gpio = container_of(gc, struct ucb1400_gpio, gc);
+
+ tmp = ucb1400_reg_read(gpio->ac97, UCB_IO_DATA) & ~mask;
+ tmp |= values & mask;
+
+ ucb1400_reg_write(gpio->ac97, UCB_IO_DATA, tmp);
+}
+
static int ucb1400_gpio_probe(struct platform_device *dev)
{
struct ucb1400_gpio *ucb = dev->dev.platform_data;
@@ -66,6 +87,8 @@ static int ucb1400_gpio_probe(struct pla
ucb->gc.direction_output = ucb1400_gpio_dir_out;
ucb->gc.get = ucb1400_gpio_get;
ucb->gc.set = ucb1400_gpio_set;
+ ucb->gc.get_block = ucb1400_gpio_get_block;
+ ucb->gc.set_block = ucb1400_gpio_set_block;
ucb->gc.can_sleep = 1;
err = gpiochip_add(&ucb->gc);
^ permalink raw reply
* [PATCH 03/11] fsmc/nand: Support multiple banks connected to controller
From: Artem Bityutskiy @ 2012-10-17 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <9748ce2483f539fb32279b8ea9df065cfdbe8ab1.1349778820.git.vipin.kumar@st.com>
On Tue, 2012-10-09 at 16:14 +0530, Vipin Kumar wrote:
> Support up to max_banks number of banks in fsmc driver.
>
> Signed-off-by: Vipin Kumar <vipin.kumar@st.com>
I tried to apply this, but it does not apply cleanly to l2-mtd.git,
which is based on 3.7-rc1.
--
Best Regards,
Artem Bityutskiy
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121017/8034920f/attachment.sig>
^ permalink raw reply
* [PATCH v9 0/3] watchdog: at91sam9_wdt: add device tree support
From: Fabio Porcedda @ 2012-10-17 12:33 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
This patchset is for adding device tree support to the
at91sam9_wdt driver.
The "timeout-sec" binding is added by another patchset already sent:
[PATCH v4 0/8] watchdog: dt: add support for the timeout-sec dt property
Changes:
v9:
- rebased over v3.7-rc1
v8:
- add __initconst to at91_wdt_dt_ids
v7:
- split the patchset
- remove timeout binding
v6:
- add watchdog core proprty timeout binding
- add as example to the orion_wdt driver the new timeout binding
v5:
- split dts commit in two, one for socs and one for boards.
v4:
- use "atmel,at91sam9260-wdt" as compatible
v3:
- add heartbeat option
- default disabled for all the soc, enable only for evk-pro3 board
- add at91sam9263 and at91sam9g45 soc
v2:
- add missing to and cc addresses
Fabio Porcedda (3):
watchdog: at91sam9_wdt: add device tree support
ARM: at91/dts: add at91sam9_wdt driver to at91sam926x, at91sam9g45
ARM: at91/dts: evk-pro3: enable watchdog
Documentation/devicetree/bindings/watchdog/atmel-wdt.txt | 15 +++++++++++++++
arch/arm/boot/dts/at91sam9260.dtsi | 6 ++++++
arch/arm/boot/dts/at91sam9263.dtsi | 6 ++++++
arch/arm/boot/dts/at91sam9g45.dtsi | 6 ++++++
arch/arm/boot/dts/evk-pro3.dts | 4 ++++
drivers/watchdog/at91sam9_wdt.c | 11 +++++++++++
6 files changed, 48 insertions(+)
create mode 100644 Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
--
1.7.11.3
^ permalink raw reply
* [PATCH v9 1/3] watchdog: at91sam9_wdt: add device tree support
From: Fabio Porcedda @ 2012-10-17 12:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477194-16802-1-git-send-email-fabio.porcedda@gmail.com>
Tested on an at91sam9260 board (evk-pro3)
Signed-off-by: Fabio Porcedda <fabio.porcedda@gmail.com>
---
Documentation/devicetree/bindings/watchdog/atmel-wdt.txt | 15 +++++++++++++++
drivers/watchdog/at91sam9_wdt.c | 11 +++++++++++
2 files changed, 26 insertions(+)
create mode 100644 Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
diff --git a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
new file mode 100644
index 0000000..2957ebb
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
@@ -0,0 +1,15 @@
+* Atmel Watchdog Timers
+
+** at91sam9-wdt
+
+Required properties:
+- compatible: must be "atmel,at91sam9260-wdt".
+- reg: physical base address of the controller and length of memory mapped
+ region.
+
+Example:
+
+ watchdog at fffffd40 {
+ compatible = "atmel,at91sam9260-wdt";
+ reg = <0xfffffd40 0x10>;
+ };
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 05e1be8..dc42e44 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -32,6 +32,7 @@
#include <linux/timer.h>
#include <linux/bitops.h>
#include <linux/uaccess.h>
+#include <linux/of.h>
#include "at91sam9_wdt.h"
@@ -302,11 +303,21 @@ static int __exit at91wdt_remove(struct platform_device *pdev)
return res;
}
+#if defined(CONFIG_OF)
+static const struct of_device_id at91_wdt_dt_ids[] __initconst = {
+ { .compatible = "atmel,at91sam9260-wdt" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_wdt_dt_ids);
+#endif
+
static struct platform_driver at91wdt_driver = {
.remove = __exit_p(at91wdt_remove),
.driver = {
.name = "at91_wdt",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_wdt_dt_ids),
},
};
--
1.7.11.3
^ permalink raw reply related
* [PATCH v9 2/3] ARM: at91/dts: add at91sam9_wdt driver to at91sam926x, at91sam9g45
From: Fabio Porcedda @ 2012-10-17 12:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477194-16802-1-git-send-email-fabio.porcedda@gmail.com>
Tested on an at91sam9260 board (evk-pro3).
Signed-off-by: Fabio Porcedda <fabio.porcedda@gmail.com>
---
arch/arm/boot/dts/at91sam9260.dtsi | 6 ++++++
arch/arm/boot/dts/at91sam9263.dtsi | 6 ++++++
arch/arm/boot/dts/at91sam9g45.dtsi | 6 ++++++
3 files changed, 18 insertions(+)
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index d410581..bfb5bb6 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -246,6 +246,12 @@
trigger-external;
};
};
+
+ watchdog at fffffd40 {
+ compatible = "atmel,at91sam9260-wdt";
+ reg = <0xfffffd40 0x10>;
+ status = "disabled";
+ };
};
nand0: nand at 40000000 {
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index 3e6e5c1..ff54612 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -195,6 +195,12 @@
#size-cells = <0>;
status = "disabled";
};
+
+ watchdog at fffffd40 {
+ compatible = "atmel,at91sam9260-wdt";
+ reg = <0xfffffd40 0x10>;
+ status = "disabled";
+ };
};
nand0: nand at 40000000 {
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 3add030..a98c00a 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -262,6 +262,12 @@
trigger-value = <0x6>;
};
};
+
+ watchdog at fffffd40 {
+ compatible = "atmel,at91sam9260-wdt";
+ reg = <0xfffffd40 0x10>;
+ status = "disabled";
+ };
};
nand0: nand at 40000000 {
--
1.7.11.3
^ permalink raw reply related
* [PATCH v9 3/3] ARM: at91/dts: evk-pro3: enable watchdog
From: Fabio Porcedda @ 2012-10-17 12:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350477194-16802-1-git-send-email-fabio.porcedda@gmail.com>
Tested on evk-pro3.
Signed-off-by: Fabio Porcedda <fabio.porcedda@gmail.com>
---
arch/arm/boot/dts/evk-pro3.dts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/evk-pro3.dts b/arch/arm/boot/dts/evk-pro3.dts
index b7354e6..ce959ee 100644
--- a/arch/arm/boot/dts/evk-pro3.dts
+++ b/arch/arm/boot/dts/evk-pro3.dts
@@ -26,6 +26,10 @@
atmel,vbus-gpio = <&pioC 5 0>;
status = "okay";
};
+
+ watchdog at fffffd40 {
+ status = "okay";
+ };
};
usb0: ohci at 00500000 {
--
1.7.11.3
^ permalink raw reply related
* [RFC] media: mx3: Add support for missing video formats
From: Benoît Thébaudeau @ 2012-10-17 12:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1138630204.7042194.1350477369863.JavaMail.root@advansee.com>
Hi all,
This is an RFC for a patch completing full video capture support on i.MX3x.
It adds missing video formats and automatic format associations according to the
underlying sensor capabilities.
It also fixes a spurious IPU interrupt issue that I have encountered on i.MX31
with earlier kernel versions. This might already have been fixed by some of the
changes that occurred in the IPU driver since then, but I still have to test if
my fix is still useful or not. Anyway, this should of course be split away to a
separate patch.
This patch has been successfully tested with i.MX35 and MT9M131, as well as some
not yet mainline OmniVision sensor drivers, using all sensor-and-SoC-supported
formats.
This patch still has to be rebased against the latest kernel and refactored in
the following way:
1. Media formats.
2. IPU formats.
3. IPU spurious interrupt fix (if still required).
4. mx3_camera formats.
Comments are welcome, especially regarding possible conflicts with other IPU
users.
Best regards,
Beno?t
Cc: Mauro Carvalho Chehab <mchehab@infradead.org>
Cc: <linux-media@vger.kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: <linux-arm-kernel@lists.infradead.org>
Signed-off-by: Beno?t Th?baudeau <benoit.thebaudeau@advansee.com>
---
.../arch/arm/plat-mxc/include/mach/ipu.h | 16 +-
.../drivers/dma/ipu/ipu_idmac.c | 241 ++++++++++++++---
.../drivers/media/video/mx3_camera.c | 264 +++++++++++++------
.../drivers/media/video/soc_mediabus.c | 276 ++++++++++++++------
.../include/linux/v4l2-mediabus.h | 11 +-
.../include/media/soc_mediabus.h | 30 ++-
6 files changed, 626 insertions(+), 212 deletions(-)
diff --git linux-3.4.5.orig/arch/arm/plat-mxc/include/mach/ipu.h linux-3.4.5/arch/arm/plat-mxc/include/mach/ipu.h
index a9221f1..f786af2 100644
--- linux-3.4.5.orig/arch/arm/plat-mxc/include/mach/ipu.h
+++ linux-3.4.5/arch/arm/plat-mxc/include/mach/ipu.h
@@ -68,25 +68,27 @@ enum pixel_fmt {
IPU_PIX_FMT_GENERIC,
IPU_PIX_FMT_RGB332,
IPU_PIX_FMT_YUV420P,
+ IPU_PIX_FMT_YVU420P,
IPU_PIX_FMT_YUV422P,
- IPU_PIX_FMT_YUV420P2,
IPU_PIX_FMT_YVU422P,
/* 2 bytes */
+ IPU_PIX_FMT_GENERIC_16,
+ IPU_PIX_FMT_RGB444,
+ IPU_PIX_FMT_RGB555,
IPU_PIX_FMT_RGB565,
- IPU_PIX_FMT_RGB666,
- IPU_PIX_FMT_BGR666,
- IPU_PIX_FMT_YUYV,
IPU_PIX_FMT_UYVY,
/* 3 bytes */
- IPU_PIX_FMT_RGB24,
+ IPU_PIX_FMT_BGR666,
+ IPU_PIX_FMT_RGB666,
IPU_PIX_FMT_BGR24,
+ IPU_PIX_FMT_RGB24,
/* 4 bytes */
IPU_PIX_FMT_GENERIC_32,
- IPU_PIX_FMT_RGB32,
IPU_PIX_FMT_BGR32,
- IPU_PIX_FMT_ABGR32,
+ IPU_PIX_FMT_RGB32,
IPU_PIX_FMT_BGRA32,
IPU_PIX_FMT_RGBA32,
+ IPU_PIX_FMT_ABGR32,
};
enum ipu_color_space {
diff --git linux-3.4.5.orig/drivers/dma/ipu/ipu_idmac.c linux-3.4.5/drivers/dma/ipu/ipu_idmac.c
index 62e3f8e..e1c97d6 100644
--- linux-3.4.5.orig/drivers/dma/ipu/ipu_idmac.c
+++ linux-3.4.5/drivers/dma/ipu/ipu_idmac.c
@@ -95,11 +95,15 @@ static uint32_t bytes_per_pixel(enum pixel_fmt fmt)
case IPU_PIX_FMT_GENERIC: /* generic data */
case IPU_PIX_FMT_RGB332:
case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YVU420P:
case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU422P:
default:
return 1;
+ case IPU_PIX_FMT_GENERIC_16: /* generic data */
+ case IPU_PIX_FMT_RGB444:
+ case IPU_PIX_FMT_RGB555:
case IPU_PIX_FMT_RGB565:
- case IPU_PIX_FMT_YUYV:
case IPU_PIX_FMT_UYVY:
return 2;
case IPU_PIX_FMT_BGR24:
@@ -108,6 +112,8 @@ static uint32_t bytes_per_pixel(enum pixel_fmt fmt)
case IPU_PIX_FMT_GENERIC_32: /* generic data */
case IPU_PIX_FMT_BGR32:
case IPU_PIX_FMT_RGB32:
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_RGBA32:
case IPU_PIX_FMT_ABGR32:
return 4;
}
@@ -297,18 +303,64 @@ static void ipu_ch_param_set_size(union chan_param_mem *params,
switch (pixel_fmt) {
case IPU_PIX_FMT_GENERIC:
- /*Represents 8-bit Generic data */
- params->pp.bpp = 3;
- params->pp.pfs = 7;
- params->pp.npb = 31;
- params->pp.sat = 2; /* SAT = use 32-bit access */
+ /* Represents 8-bit Generic data */
+ params->ip.bpp = 3;
+ params->ip.pfs = 7;
+ params->ip.npb = 31;
+ params->ip.sat = 2; /* SAT = use 32-bit access */
+ break;
+ case IPU_PIX_FMT_GENERIC_16:
+ /* Represents 16-bit Generic data */
+ params->ip.bpp = 2;
+ params->ip.pfs = 7;
+ params->ip.npb = 15;
+ params->ip.sat = 2; /* SAT = use 32-bit access */
break;
case IPU_PIX_FMT_GENERIC_32:
- /*Represents 32-bit Generic data */
- params->pp.bpp = 0;
- params->pp.pfs = 7;
- params->pp.npb = 7;
- params->pp.sat = 2; /* SAT = use 32-bit access */
+ /* Represents 32-bit Generic data */
+ params->ip.bpp = 0;
+ params->ip.pfs = 7;
+ params->ip.npb = 7;
+ params->ip.sat = 2; /* SAT = use 32-bit access */
+ break;
+ case IPU_PIX_FMT_RGB332:
+ params->ip.bpp = 3;
+ params->ip.pfs = 4;
+ params->ip.npb = 31;
+ params->ip.sat = 2; /* SAT = 32-bit access */
+ params->ip.ofs0 = 0; /* Red bit offset */
+ params->ip.ofs1 = 3; /* Green bit offset */
+ params->ip.ofs2 = 6; /* Blue bit offset */
+ params->ip.ofs3 = 8; /* Alpha bit offset */
+ params->ip.wid0 = 2; /* Red bit width - 1 */
+ params->ip.wid1 = 2; /* Green bit width - 1 */
+ params->ip.wid2 = 1; /* Blue bit width - 1 */
+ break;
+ case IPU_PIX_FMT_RGB444:
+ params->ip.bpp = 2;
+ params->ip.pfs = 4;
+ params->ip.npb = 15;
+ params->ip.sat = 2; /* SAT = 32-bit access */
+ params->ip.ofs0 = 4; /* Red bit offset */
+ params->ip.ofs1 = 8; /* Green bit offset */
+ params->ip.ofs2 = 12; /* Blue bit offset */
+ params->ip.ofs3 = 16; /* Alpha bit offset */
+ params->ip.wid0 = 3; /* Red bit width - 1 */
+ params->ip.wid1 = 3; /* Green bit width - 1 */
+ params->ip.wid2 = 3; /* Blue bit width - 1 */
+ break;
+ case IPU_PIX_FMT_RGB555:
+ params->ip.bpp = 2;
+ params->ip.pfs = 4;
+ params->ip.npb = 15;
+ params->ip.sat = 2; /* SAT = 32-bit access */
+ params->ip.ofs0 = 1; /* Red bit offset */
+ params->ip.ofs1 = 6; /* Green bit offset */
+ params->ip.ofs2 = 11; /* Blue bit offset */
+ params->ip.ofs3 = 16; /* Alpha bit offset */
+ params->ip.wid0 = 4; /* Red bit width - 1 */
+ params->ip.wid1 = 4; /* Green bit width - 1 */
+ params->ip.wid2 = 4; /* Blue bit width - 1 */
break;
case IPU_PIX_FMT_RGB565:
params->ip.bpp = 2;
@@ -326,7 +378,7 @@ static void ipu_ch_param_set_size(union chan_param_mem *params,
case IPU_PIX_FMT_BGR24:
params->ip.bpp = 1; /* 24 BPP & RGB PFS */
params->ip.pfs = 4;
- params->ip.npb = 7;
+ params->ip.npb = 9;
params->ip.sat = 2; /* SAT = 32-bit access */
params->ip.ofs0 = 0; /* Red bit offset */
params->ip.ofs1 = 8; /* Green bit offset */
@@ -339,7 +391,7 @@ static void ipu_ch_param_set_size(union chan_param_mem *params,
case IPU_PIX_FMT_RGB24:
params->ip.bpp = 1; /* 24 BPP & RGB PFS */
params->ip.pfs = 4;
- params->ip.npb = 7;
+ params->ip.npb = 9;
params->ip.sat = 2; /* SAT = 32-bit access */
params->ip.ofs0 = 16; /* Red bit offset */
params->ip.ofs1 = 8; /* Green bit offset */
@@ -383,37 +435,45 @@ static void ipu_ch_param_set_size(union chan_param_mem *params,
case IPU_PIX_FMT_UYVY:
params->ip.bpp = 2;
params->ip.pfs = 6;
- params->ip.npb = 7;
+ params->ip.npb = 15;
params->ip.sat = 2; /* SAT = 32-bit access */
break;
- case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
- params->ip.bpp = 3;
- params->ip.pfs = 3;
- params->ip.npb = 7;
- params->ip.sat = 2; /* SAT = 32-bit access */
+ params->pp.bpp = 3;
+ params->pp.pfs = 3;
+ params->pp.npb = 15;
+ params->pp.sat = 2; /* SAT = 32-bit access */
u_offset = stride * height;
v_offset = u_offset + u_offset / 4;
ipu_ch_param_set_plane_offset(params, u_offset, v_offset);
break;
- case IPU_PIX_FMT_YVU422P:
- params->ip.bpp = 3;
- params->ip.pfs = 2;
- params->ip.npb = 7;
- params->ip.sat = 2; /* SAT = 32-bit access */
+ case IPU_PIX_FMT_YVU420P:
+ params->pp.bpp = 3;
+ params->pp.pfs = 3;
+ params->pp.npb = 15;
+ params->pp.sat = 2; /* SAT = 32-bit access */
v_offset = stride * height;
- u_offset = v_offset + v_offset / 2;
+ u_offset = v_offset + v_offset / 4;
ipu_ch_param_set_plane_offset(params, u_offset, v_offset);
break;
case IPU_PIX_FMT_YUV422P:
- params->ip.bpp = 3;
- params->ip.pfs = 2;
- params->ip.npb = 7;
- params->ip.sat = 2; /* SAT = 32-bit access */
+ params->pp.bpp = 3;
+ params->pp.pfs = 2;
+ params->pp.npb = 15;
+ params->pp.sat = 2; /* SAT = 32-bit access */
u_offset = stride * height;
v_offset = u_offset + u_offset / 2;
ipu_ch_param_set_plane_offset(params, u_offset, v_offset);
break;
+ case IPU_PIX_FMT_YVU422P:
+ params->pp.bpp = 3;
+ params->pp.pfs = 2;
+ params->pp.npb = 15;
+ params->pp.sat = 2; /* SAT = 32-bit access */
+ v_offset = stride * height;
+ u_offset = v_offset + v_offset / 2;
+ ipu_ch_param_set_plane_offset(params, u_offset, v_offset);
+ break;
default:
dev_err(ipu_data.dev,
"mx3 ipu: unimplemented pixel format %d\n", pixel_fmt);
@@ -423,6 +483,17 @@ static void ipu_ch_param_set_size(union chan_param_mem *params,
params->pp.nsb = 1;
}
+static uint16_t ipu_ch_param_get_burst_size(const union chan_param_mem *params)
+{
+ return params->pp.npb + 1;
+}
+
+static void ipu_ch_param_set_burst_size(union chan_param_mem *params,
+ uint16_t burst_pixels)
+{
+ params->pp.npb = burst_pixels - 1;
+}
+
static void ipu_ch_param_set_buffer(union chan_param_mem *params,
dma_addr_t buf0, dma_addr_t buf1)
{
@@ -498,6 +569,9 @@ static int calc_resize_coeffs(uint32_t in_size, uint32_t out_size,
static enum ipu_color_space format_to_colorspace(enum pixel_fmt fmt)
{
switch (fmt) {
+ case IPU_PIX_FMT_RGB332:
+ case IPU_PIX_FMT_RGB444:
+ case IPU_PIX_FMT_RGB555:
case IPU_PIX_FMT_RGB565:
case IPU_PIX_FMT_BGR24:
case IPU_PIX_FMT_RGB24:
@@ -665,6 +739,7 @@ static int ipu_init_channel_buffer(struct idmac_channel *ichan,
unsigned long flags;
uint32_t reg;
uint32_t stride_bytes;
+ uint16_t burst_pixels;
stride_bytes = stride * bytes_per_pixel(pixel_fmt);
@@ -685,6 +760,29 @@ static int ipu_init_channel_buffer(struct idmac_channel *ichan,
ipu_ch_param_set_size(¶ms, pixel_fmt, width, height, stride_bytes);
ipu_ch_param_set_buffer(¶ms, phyaddr_0, phyaddr_1);
ipu_ch_param_set_rotation(¶ms, rot_mode);
+ /*
+ * ipu_ch_param_set_size() above has set the optimal burst size for each
+ * format, which also helps avoiding hanging channels:
+ * - 16 pixels for planar formats,
+ * - 8, 10, 16, 32 or 64 pixels for interleaved formats.
+ */
+ burst_pixels = ipu_ch_param_get_burst_size(¶ms);
+ /* Some channels (rotation) have restriction on burst length */
+ switch (channel) {
+ case IDMAC_IC_0:
+ case IDMAC_IC_7:
+ default:
+ /* There is no restriction for these channels. */
+ break;
+ case IDMAC_SDC_0:
+ case IDMAC_SDC_1:
+ if (burst_pixels >= 16)
+ burst_pixels = 16;
+ else
+ burst_pixels = 8;
+ break;
+ }
+ ipu_ch_param_set_burst_size(¶ms, burst_pixels);
spin_lock_irqsave(&ipu->lock, flags);
@@ -1081,7 +1179,18 @@ static int ipu_disable_channel(struct idmac *idmac, struct idmac_channel *ichan,
if (wait_for_stop && channel != IDMAC_SDC_1 && channel != IDMAC_SDC_0) {
timeout = 40;
- /* This waiting always fails. Related to spurious irq problem */
+ /*
+ * This waiting sometimes fails because the channel has hung.
+ * This can happen if the input stream is stopped for an active
+ * IDMAC channel.
+ * E.g., soc_camera_streamoff() induces a call to
+ * mx3_videobuf_release(), which does not (and does not have to)
+ * wait for the completion of DMA transfers before releasing the
+ * corresponding buffers, then soc_camera_streamoff() invokes
+ * sd->video->s_stream(), which may hence stop the input stream
+ * for an active IDMAC channel. The current code is called only
+ * afterwards.
+ */
while ((idmac_read_icreg(ipu, IDMAC_CHA_BUSY) & chan_mask) ||
(ipu_channel_status(ipu, channel) == TASK_STAT_ACTIVE)) {
timeout--;
@@ -1164,7 +1273,7 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
dma_async_tx_callback callback;
void *callback_param;
bool done = false;
- u32 ready0, ready1, curbuf, err;
+ u32 ready0, ready1, curbuf, err, busy;
unsigned long flags;
/* IDMAC has cleared the respective BUFx_RDY bit, we manage the buffer */
@@ -1177,7 +1286,15 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
ready1 = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF1_RDY);
curbuf = idmac_read_ipureg(&ipu_data, IPU_CHA_CUR_BUF);
err = idmac_read_ipureg(&ipu_data, IPU_INT_STAT_4);
+ busy = idmac_read_icreg(&ipu_data, IDMAC_CHA_BUSY);
+ /*
+ * If the buffer transfer is too slow compared to the frame rate, an
+ * NF will occur before the expected channel EOF, triggering an
+ * NFB4EOF_ERR.
+ * This error interrupt has not been requested, so the code is handling
+ * the first channel EOF interrupt following this error.
+ */
if (err & (1 << chan_id)) {
idmac_write_ipureg(&ipu_data, 1 << chan_id, IPU_INT_STAT_4);
spin_unlock_irqrestore(&ipu_data.lock, flags);
@@ -1187,6 +1304,19 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
* you can force channel re-enable on the next tx_submit(), but
* this is dirty - think about descriptors with multiple
* sg elements.
+ * Passing back the incomplete buffer to the submitter would
+ * also be dirty.
+ * Reusing the incomplete buffer after the next one would imply
+ * changing the callback call order, which may affect the
+ * submitter.
+ * The cleanest thing to do here would be to tell the submitter
+ * that its buffer has been dropped and to handle the completion
+ * of the next buffer (i.e. the current interrupt).
+ * Unfortunately, there does not seem to be any means of doing
+ * that.
+ * If this error is not properly handled, the channel will hang
+ * since this will let the channel consume its two buffers
+ * without submitting new buffers.
*/
dev_warn(dev, "NFB4EOF on channel %d, ready %x, %x, cur %x\n",
chan_id, ready0, ready1, curbuf);
@@ -1196,6 +1326,51 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
/* Other interrupts do not interfere with this channel */
spin_lock(&ichan->lock);
+ /*
+ * The busy status has to be checked here in order to avoid considering
+ * a legitimate interrupt as a spurious interrupt.
+ * Actually, when double-buffering is used, the normal sequence for
+ * DMAIC_7 is:
+ * - Initialization of the channel with DBMS = 1 and two buffers:
+ * BUF0_RDY = 1, BUF1_RDY = 1, CUR_BUF = 1, BUSY = 0
+ * - First CSI_NF: The channel starts handling buffer 0:
+ * BUF0_RDY = 0, BUF1_RDY = 1, CUR_BUF = 0, BUSY = 1
+ * - CSI_EOF: The channel stops handling buffer 0:
+ * BUF0_RDY = 0, BUF1_RDY = 1, CUR_BUF = 0, BUSY = 0
+ * - EOF: The channel signals buffer 0 completion:
+ * BUF0_RDY = 0, BUF1_RDY = 1, CUR_BUF = 0, BUSY = 0
+ * - The interrupt handler prepares buffer 0 with the next element:
+ * BUF0_RDY = 1, BUF1_RDY = 1, CUR_BUF = 0, BUSY = 0
+ * - CSI_NF: The channel starts handling buffer 1:
+ * BUF0_RDY = 1, BUF1_RDY = 0, CUR_BUF = 1, BUSY = 1
+ * - CSI_EOF: The channel stops handling buffer 1:
+ * BUF0_RDY = 1, BUF1_RDY = 0, CUR_BUF = 1, BUSY = 0
+ * - EOF: The channel signals buffer 1 completion:
+ * BUF0_RDY = 1, BUF1_RDY = 0, CUR_BUF = 1, BUSY = 0
+ * - The interrupt handler prepares buffer 1 with the next element:
+ * BUF0_RDY = 1, BUF1_RDY = 1, CUR_BUF = 1, BUSY = 0
+ * - CSI_NF: The channel starts handling buffer 0:
+ * BUF0_RDY = 0, BUF1_RDY = 1, CUR_BUF = 0, BUSY = 1
+ * - ...
+ * Hence, a DMAIC_7_EOF interrupt can be received with CUR_BUF being the
+ * active buffer if there is enough time between two consecutive CSI
+ * frames. This is normal if the channel is not busy. This interrupt
+ * must be used to prepare the channel for a new buffer.
+ * If the channel is busy however, this is either a shared interrupt
+ * that is not for this channel, or a legitimate interrupt that has been
+ * delayed beyond the allowed update time window.
+ */
+ if (unlikely(chan_id != IDMAC_SDC_0 && chan_id != IDMAC_SDC_1 &&
+ (busy >> chan_id) & 1 &&
+ ((curbuf >> chan_id) & 1) == ichan->active_buffer)) {
+ spin_unlock(&ichan->lock);
+ dev_dbg(dev,
+ "IRQ on active buffer on channel %x, active "
+ "%d, ready %x, %x, current %x!\n", chan_id,
+ ichan->active_buffer, ready0, ready1, curbuf);
+ return IRQ_NONE;
+ }
+
if (unlikely((ichan->active_buffer && (ready1 >> chan_id) & 1) ||
(!ichan->active_buffer && (ready0 >> chan_id) & 1)
)) {
@@ -1219,8 +1394,8 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
/*
* active_buffer is a software flag, it shows which buffer we are
- * currently expecting back from the hardware, IDMAC should be
- * processing the other buffer already
+ * currently expecting back from the hardware, IDMAC should have
+ * finished processing this buffer already
*/
sg = &ichan->sg[ichan->active_buffer];
sgnext = ichan->sg[!ichan->active_buffer];
diff --git linux-3.4.5.orig/drivers/media/video/mx3_camera.c linux-3.4.5/drivers/media/video/mx3_camera.c
index 93c35ef..50c53bf 100644
--- linux-3.4.5.orig/drivers/media/video/mx3_camera.c
+++ linux-3.4.5/drivers/media/video/mx3_camera.c
@@ -243,17 +243,66 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
return 0;
}
-static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc)
+static u32 pixelcode_to_csi_fmt(enum v4l2_mbus_pixelcode code)
{
- /* Add more formats as need arises and test possibilities appear... */
- switch (fourcc) {
- case V4L2_PIX_FMT_RGB24:
- return IPU_PIX_FMT_RGB24;
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_RGB565:
+ switch (code) {
+ /* CSI input formats (i.e. sensor output formats) */
+ case V4L2_MBUS_FMT_RGB24_3X8_BE:
+ return CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ return CSI_SENS_CONF_DATA_FMT_YUV422;
+ default:
+ return CSI_SENS_CONF_DATA_FMT_BAYER;
+ }
+}
+
+static enum pixel_fmt to_ipu_pix(enum v4l2_mbus_pixelcode code, __u32 fourcc)
+{
+ const struct soc_mbus_pixelfmt *fmt = soc_mbus_get_fmtdesc(code);
+
+ if (!fmt)
+ return -EINVAL;
+
+ switch (code) {
+ /* CSI input formats (i.e. sensor output formats) */
+ case V4L2_MBUS_FMT_RGB24_3X8_BE:
+ switch (fourcc) {
+ /* IDMAC output formats */
+ case V4L2_PIX_FMT_RGB332:
+ return IPU_PIX_FMT_RGB332;
+ case V4L2_PIX_FMT_RGB444:
+ return IPU_PIX_FMT_RGB444;
+ case V4L2_PIX_FMT_RGB555:
+ return IPU_PIX_FMT_RGB555;
+ case V4L2_PIX_FMT_RGB565:
+ return IPU_PIX_FMT_RGB565;
+ case V4L2_PIX_FMT_BGR24:
+ return IPU_PIX_FMT_BGR24;
+ case V4L2_PIX_FMT_RGB24:
+ return IPU_PIX_FMT_RGB24;
+ }
+ break;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ switch (fourcc) {
+ /* IDMAC output formats */
+ case V4L2_PIX_FMT_YVU420:
+ return IPU_PIX_FMT_YVU420P;
+ case V4L2_PIX_FMT_UYVY:
+ return IPU_PIX_FMT_UYVY;
+ case V4L2_PIX_FMT_YUV422P:
+ return IPU_PIX_FMT_YUV422P;
+ case V4L2_PIX_FMT_YUV420:
+ return IPU_PIX_FMT_YUV420P;
+ }
+ break;
default:
- return IPU_PIX_FMT_GENERIC;
+ if (fmt->bits_per_sample <= 8)
+ return IPU_PIX_FMT_GENERIC;
+ else if (fmt->bits_per_sample <= 16)
+ return IPU_PIX_FMT_GENERIC_16;
+ break;
}
+ return -EINVAL;
}
static void mx3_videobuf_queue(struct vb2_buffer *vb)
@@ -268,6 +317,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
struct idmac_video_param *video = &ichan->params.video;
const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt;
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, host_fmt);
+ s32 width = icd->user_width;
unsigned long flags;
dma_cookie_t cookie;
size_t new_size;
@@ -304,29 +354,30 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
vb2_set_plane_payload(vb, 0, new_size);
/* This is the configuration of one sg-element */
- video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc);
+ video->out_pixel_fmt = to_ipu_pix(icd->current_fmt->code,
+ host_fmt->fourcc);
+ BUG_ON(video->out_pixel_fmt < 0);
- if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) {
+ if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC ||
+ video->out_pixel_fmt == IPU_PIX_FMT_GENERIC_16) {
/*
* If the IPU DMA channel is configured to transfer generic
- * 8-bit data, we have to set up the geometry parameters
- * correctly, according to the current pixel format. The DMA
- * horizontal parameters in this case are expressed in bytes,
- * not in pixels.
+ * data, we have to set up the geometry parameters correctly,
+ * according to the current pixel format. The DMA horizontal
+ * parameters in this case are expressed in samples, not in
+ * pixels.
*/
- video->out_width = bytes_per_line;
- video->out_height = icd->user_height;
- video->out_stride = bytes_per_line;
- } else {
- /*
- * For IPU known formats the pixel unit will be managed
- * successfully by the IPU code
- */
- video->out_width = icd->user_width;
- video->out_height = icd->user_height;
- video->out_stride = icd->user_width;
+ unsigned int num, den;
+ int ret = soc_mbus_samples_per_pixel(icd->current_fmt->host_fmt,
+ &num, &den);
+ BUG_ON(ret < 0);
+ width = width * num / den;
}
+ video->out_width = width;
+ video->out_height = icd->user_height;
+ video->out_stride = width;
+
#ifdef DEBUG
/* helps to see what DMA actually has written */
if (vb2_plane_vaddr(vb, 0))
@@ -452,7 +503,7 @@ static struct vb2_ops mx3_videobuf_ops = {
};
static int mx3_camera_init_videobuf(struct vb2_queue *q,
- struct soc_camera_device *icd)
+ struct soc_camera_device *icd)
{
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR;
@@ -562,7 +613,7 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam,
{
/*
* If requested data width is supported by the platform, use it or any
- * possible lower value - i.MX31 is smart enough to shift bits
+ * possible lower value - i.MX3x is smart enough to shift bits
*/
if (buswidth > fls(mx3_cam->width_flags))
return -EINVAL;
@@ -587,16 +638,16 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam,
}
static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
- const unsigned int depth)
+ unsigned int buswidth)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
unsigned long bus_flags, common_flags;
- int ret = test_platform_param(mx3_cam, depth, &bus_flags);
+ int ret = test_platform_param(mx3_cam, buswidth, &bus_flags);
- dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret);
+ dev_dbg(icd->parent, "requested bus width %d bit: %d\n", buswidth, ret);
if (ret < 0)
return ret;
@@ -635,30 +686,77 @@ static bool chan_filter(struct dma_chan *chan, void *arg)
pdata->dma_dev == chan->device->dev;
}
-static const struct soc_mbus_pixelfmt mx3_camera_formats[] = {
+static const struct soc_mbus_pixelfmt mx3_camera_formats_rgb[] = {
{
- .fourcc = V4L2_PIX_FMT_SBGGR8,
- .name = "Bayer BGGR (sRGB) 8 bit",
+ .fourcc = V4L2_PIX_FMT_RGB332,
+ .name = "Packed RGB332",
.bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_1X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB444,
+ .name = "Packed RGB444",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB555,
+ .name = "Packed RGB555",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .name = "Packed RGB565",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
+ }, {
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .name = "BGR24",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_3X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .name = "RGB24",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_3X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+};
+
+static const struct soc_mbus_pixelfmt mx3_camera_formats_yuv[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .name = "Planar YVU 4:2:0 12 bit",
+ .bits_per_sample = 12,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
}, {
- .fourcc = V4L2_PIX_FMT_GREY,
- .name = "Monochrome 8 bit",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .name = "Interleaved YUV 4:2:2 (UYVY) 16 bit",
.bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .name = "Planar YUV 4:2:2 16 bit",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .name = "Planar YUV 4:2:0 12 bit",
+ .bits_per_sample = 12,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
},
};
-/* This will be corrected as we get more formats */
-static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
+static bool mx3_camera_passthrough_supported(const struct soc_mbus_pixelfmt *fmt)
{
- return fmt->packing == SOC_MBUS_PACKING_NONE ||
- (fmt->bits_per_sample == 8 &&
- fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
- (fmt->bits_per_sample > 8 &&
- fmt->packing == SOC_MBUS_PACKING_EXTEND16);
+ return fmt->bits_per_sample == 8 && fmt->order == SOC_MBUS_ORDER_LE;
}
static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx,
@@ -666,9 +764,9 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->parent;
- int formats = 0, ret;
+ int formats = 0, k, n = 0, ret;
enum v4l2_mbus_pixelcode code;
- const struct soc_mbus_pixelfmt *fmt;
+ const struct soc_mbus_pixelfmt *fmt, *mx3_camera_formats;
ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
if (ret < 0)
@@ -688,41 +786,42 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
return 0;
switch (code) {
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- formats++;
- if (xlate) {
- xlate->host_fmt = &mx3_camera_formats[0];
- xlate->code = code;
- xlate++;
- dev_dbg(dev, "Providing format %s using code %d\n",
- mx3_camera_formats[0].name, code);
- }
+ /* CSI input formats (i.e. sensor output formats) */
+ case V4L2_MBUS_FMT_RGB24_3X8_BE:
+ mx3_camera_formats = mx3_camera_formats_rgb;
+ n = ARRAY_SIZE(mx3_camera_formats_rgb);
+ break;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mx3_camera_formats = mx3_camera_formats_yuv;
+ n = ARRAY_SIZE(mx3_camera_formats_yuv);
break;
case V4L2_MBUS_FMT_Y10_1X10:
- formats++;
- if (xlate) {
- xlate->host_fmt = &mx3_camera_formats[1];
- xlate->code = code;
- xlate++;
- dev_dbg(dev, "Providing format %s using code %d\n",
- mx3_camera_formats[1].name, code);
- }
+ mx3_camera_formats = soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_Y16_1X16);
+ n = 1;
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_1X10:
+ mx3_camera_formats = soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_SBGGR16_1X16);
+ n = 1;
break;
default:
- if (!mx3_camera_packing_supported(fmt))
- return 0;
+ if (mx3_camera_passthrough_supported(fmt)) {
+ mx3_camera_formats = fmt;
+ n = 1;
+ }
+ break;
}
- /* Generic pass-through */
- formats++;
- if (xlate) {
- xlate->host_fmt = fmt;
+ formats += n;
+ for (k = 0; xlate && k < n; k++) {
+ BUG_ON(!mx3_camera_formats);
+ xlate->host_fmt = &mx3_camera_formats[k];
xlate->code = code;
- dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n",
- (fmt->fourcc >> (0*8)) & 0xFF,
- (fmt->fourcc >> (1*8)) & 0xFF,
- (fmt->fourcc >> (2*8)) & 0xFF,
- (fmt->fourcc >> (3*8)) & 0xFF);
+ dev_dbg(dev, "Providing format %c%c%c%c from media bus data format %d\n",
+ (xlate->host_fmt->fourcc >> (0*8)) & 0xFF,
+ (xlate->host_fmt->fourcc >> (1*8)) & 0xFF,
+ (xlate->host_fmt->fourcc >> (2*8)) & 0xFF,
+ (xlate->host_fmt->fourcc >> (3*8)) & 0xFF,
+ code);
xlate++;
}
@@ -731,11 +830,15 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
static void configure_geometry(struct mx3_camera_dev *mx3_cam,
unsigned int width, unsigned int height,
- const struct soc_mbus_pixelfmt *fmt)
+ enum v4l2_mbus_pixelcode code)
{
u32 ctrl, width_field, height_field;
+ const struct soc_mbus_pixelfmt *fmt;
- if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) {
+ fmt = soc_mbus_get_fmtdesc(code);
+ BUG_ON(!fmt);
+
+ if (pixelcode_to_csi_fmt(code) == CSI_SENS_CONF_DATA_FMT_BAYER) {
/*
* As the CSI will be configured to output BAYER, here
* the width parameter count the number of samples to
@@ -835,8 +938,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
}
if (mf.width != icd->user_width || mf.height != icd->user_height)
- configure_geometry(mx3_cam, mf.width, mf.height,
- icd->current_fmt->host_fmt);
+ configure_geometry(mx3_cam, mf.width, mf.height, mf.code);
dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
mf.width, mf.height);
@@ -874,7 +976,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
* mxc_v4l2_s_fmt()
*/
- configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt);
+ configure_geometry(mx3_cam, pix->width, pix->height, xlate->code);
mf.width = pix->width;
mf.height = pix->height;
@@ -1089,10 +1191,8 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd)
(3 << CSI_SENS_CONF_DATA_FMT_SHIFT) |
(3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT));
- /* TODO: Support RGB and YUV formats */
-
- /* This has been set in mx3_camera_activate(), but we clear it above */
- sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
+ /* Set data format */
+ sens_conf |= pixelcode_to_csi_fmt(icd->current_fmt->code);
if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
@@ -1104,7 +1204,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd)
sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
/* Just do what we're asked to do */
- switch (xlate->host_fmt->bits_per_sample) {
+ switch (buswidth) {
case 4:
dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
break;
diff --git linux-3.4.5.orig/drivers/media/video/soc_mediabus.c linux-3.4.5/drivers/media/video/soc_mediabus.c
index cf7f219..c9a2cce 100644
--- linux-3.4.5.orig/drivers/media/video/soc_mediabus.c
+++ linux-3.4.5/drivers/media/video/soc_mediabus.c
@@ -17,37 +17,37 @@
static const struct soc_mbus_lookup mbus_fmt[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .code = V4L2_MBUS_FMT_RGB332_1X8,
.fmt = {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .name = "YUYV",
+ .fourcc = V4L2_PIX_FMT_RGB332,
+ .name = "RGB332",
.bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .packing = SOC_MBUS_PACKING_1X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
.fmt = {
- .fourcc = V4L2_PIX_FMT_YVYU,
- .name = "YVYU",
+ .fourcc = V4L2_PIX_FMT_RGB444,
+ .name = "RGB444",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_LE,
+ .order = SOC_MBUS_ORDER_BE,
},
}, {
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
.fmt = {
- .fourcc = V4L2_PIX_FMT_UYVY,
- .name = "UYVY",
+ .fourcc = V4L2_PIX_FMT_RGB444,
+ .name = "RGB444",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
.fmt = {
- .fourcc = V4L2_PIX_FMT_VYUY,
- .name = "VYUY",
+ .fourcc = V4L2_PIX_FMT_RGB555X,
+ .name = "RGB555X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
@@ -62,10 +62,10 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
.fmt = {
- .fourcc = V4L2_PIX_FMT_RGB555X,
- .name = "RGB555X",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .name = "RGB565X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
@@ -80,30 +80,21 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .code = V4L2_MBUS_FMT_RGB24_3X8_BE,
.fmt = {
- .fourcc = V4L2_PIX_FMT_RGB565X,
- .name = "RGB565X",
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .name = "RGB24",
.bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .packing = SOC_MBUS_PACKING_3X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR8_1X8,
+ .code = V4L2_MBUS_FMT_RGB24_3X8_LE,
.fmt = {
- .fourcc = V4L2_PIX_FMT_SBGGR8,
- .name = "Bayer 8 BGGR",
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .name = "BGR24",
.bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_NONE,
- .order = SOC_MBUS_ORDER_LE,
- },
-}, {
- .code = V4L2_MBUS_FMT_SBGGR10_1X10,
- .fmt = {
- .fourcc = V4L2_PIX_FMT_SBGGR10,
- .name = "Bayer 10 BGGR",
- .bits_per_sample = 10,
- .packing = SOC_MBUS_PACKING_EXTEND16,
+ .packing = SOC_MBUS_PACKING_3X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
}, {
@@ -116,84 +107,75 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_Y10_1X10,
+ .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
.fmt = {
- .fourcc = V4L2_PIX_FMT_Y10,
- .name = "Grey 10bit",
- .bits_per_sample = 10,
- .packing = SOC_MBUS_PACKING_EXTEND16,
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .name = "YUYV 4:2:0",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_1_5X8,
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+ .code = V4L2_MBUS_FMT_YVYU8_1_5X8,
.fmt = {
- .fourcc = V4L2_PIX_FMT_SBGGR10,
- .name = "Bayer 10 BGGR",
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .name = "YVYU 4:2:0",
.bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .packing = SOC_MBUS_PACKING_1_5X8,
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.fmt = {
- .fourcc = V4L2_PIX_FMT_SBGGR10,
- .name = "Bayer 10 BGGR",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .name = "UYVY",
.bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADLO,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
.fmt = {
- .fourcc = V4L2_PIX_FMT_SBGGR10,
- .name = "Bayer 10 BGGR",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .name = "VYUY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_BE,
+ .order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.fmt = {
- .fourcc = V4L2_PIX_FMT_SBGGR10,
- .name = "Bayer 10 BGGR",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .name = "YUYV",
.bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_2X8_PADLO,
- .order = SOC_MBUS_ORDER_BE,
- },
-}, {
- .code = V4L2_MBUS_FMT_JPEG_1X8,
- .fmt = {
- .fourcc = V4L2_PIX_FMT_JPEG,
- .name = "JPEG",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_VARIABLE,
- .order = SOC_MBUS_ORDER_LE,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
.fmt = {
- .fourcc = V4L2_PIX_FMT_RGB444,
- .name = "RGB444",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .name = "YVYU",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_BE,
+ .order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
+ .code = V4L2_MBUS_FMT_Y10_1X10,
.fmt = {
- .fourcc = V4L2_PIX_FMT_YUV420,
- .name = "YUYV 4:2:0",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_1_5X8,
+ .fourcc = V4L2_PIX_FMT_Y10,
+ .name = "Grey 10bit",
+ .bits_per_sample = 10,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_YVYU8_1_5X8,
+ .code = V4L2_MBUS_FMT_Y12_1X12,
.fmt = {
- .fourcc = V4L2_PIX_FMT_YVU420,
- .name = "YVYU 4:2:0",
- .bits_per_sample = 8,
- .packing = SOC_MBUS_PACKING_1_5X8,
+ .fourcc = V4L2_PIX_FMT_Y12,
+ .name = "Grey 12bit",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
},
}, {
@@ -233,6 +215,33 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.order = SOC_MBUS_ORDER_LE,
},
}, {
+ .code = V4L2_MBUS_FMT_Y16_1X16,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_Y16,
+ .name = "Grey 16bit",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR8_1X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .name = "Bayer 8 BGGR",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGBRG8_1X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .name = "Bayer 8 GBRG",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
.code = V4L2_MBUS_FMT_SGRBG8_1X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_SGRBG8,
@@ -242,15 +251,69 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.order = SOC_MBUS_ORDER_LE,
},
}, {
+ .code = V4L2_MBUS_FMT_SRGGB8_1X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .name = "Bayer 8 RGGB",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
.code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_SGRBG10DPCM8,
- .name = "Bayer 10 BGGR DPCM 8",
+ .name = "Bayer 10 GRBG DPCM 8",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
},
}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .name = "Bayer 10 BGGR",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .name = "Bayer 10 BGGR",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .name = "Bayer 10 BGGR",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADLO,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .name = "Bayer 10 BGGR",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADLO,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .name = "Bayer 10 BGGR",
+ .bits_per_sample = 10,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
.code = V4L2_MBUS_FMT_SGBRG10_1X10,
.fmt = {
.fourcc = V4L2_PIX_FMT_SGBRG10,
@@ -313,6 +376,24 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
},
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR16_1X16,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SBGGR16,
+ .name = "Bayer 16 BGGR",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .name = "JPEG",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_VARIABLE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
},
};
@@ -321,18 +402,33 @@ int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
{
switch (mf->packing) {
case SOC_MBUS_PACKING_NONE:
+ case SOC_MBUS_PACKING_1X8_PADHI:
+ case SOC_MBUS_PACKING_1X8_PADLO:
+ case SOC_MBUS_PACKING_EXTEND8:
case SOC_MBUS_PACKING_EXTEND16:
+ case SOC_MBUS_PACKING_EXTEND24:
+ case SOC_MBUS_PACKING_EXTEND32:
*numerator = 1;
*denominator = 1;
return 0;
+ case SOC_MBUS_PACKING_1_5X8:
+ *numerator = 3;
+ *denominator = 2;
+ return 0;
case SOC_MBUS_PACKING_2X8_PADHI:
case SOC_MBUS_PACKING_2X8_PADLO:
*numerator = 2;
*denominator = 1;
return 0;
- case SOC_MBUS_PACKING_1_5X8:
+ case SOC_MBUS_PACKING_3X8_PADHI:
+ case SOC_MBUS_PACKING_3X8_PADLO:
*numerator = 3;
- *denominator = 2;
+ *denominator = 1;
+ return 0;
+ case SOC_MBUS_PACKING_4X8_PADHI:
+ case SOC_MBUS_PACKING_4X8_PADLO:
+ *numerator = 4;
+ *denominator = 1;
return 0;
case SOC_MBUS_PACKING_VARIABLE:
*numerator = 0;
@@ -348,12 +444,24 @@ s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
switch (mf->packing) {
case SOC_MBUS_PACKING_NONE:
return width * mf->bits_per_sample / 8;
+ case SOC_MBUS_PACKING_1X8_PADHI:
+ case SOC_MBUS_PACKING_1X8_PADLO:
+ case SOC_MBUS_PACKING_EXTEND8:
+ return width * 1;
+ case SOC_MBUS_PACKING_1_5X8:
+ return width * 3 / 2;
case SOC_MBUS_PACKING_2X8_PADHI:
case SOC_MBUS_PACKING_2X8_PADLO:
case SOC_MBUS_PACKING_EXTEND16:
return width * 2;
- case SOC_MBUS_PACKING_1_5X8:
- return width * 3 / 2;
+ case SOC_MBUS_PACKING_3X8_PADHI:
+ case SOC_MBUS_PACKING_3X8_PADLO:
+ case SOC_MBUS_PACKING_EXTEND24:
+ return width * 3;
+ case SOC_MBUS_PACKING_4X8_PADHI:
+ case SOC_MBUS_PACKING_4X8_PADLO:
+ case SOC_MBUS_PACKING_EXTEND32:
+ return width * 4;
case SOC_MBUS_PACKING_VARIABLE:
return 0;
}
diff --git linux-3.4.5.orig/include/linux/v4l2-mediabus.h linux-3.4.5/include/linux/v4l2-mediabus.h
index 5ea7f75..57a9fc9 100644
--- linux-3.4.5.orig/include/linux/v4l2-mediabus.h
+++ linux-3.4.5/include/linux/v4l2-mediabus.h
@@ -37,7 +37,8 @@
enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_FIXED = 0x0001,
- /* RGB - next is 0x1009 */
+ /* RGB - next is 0x100c */
+ V4L2_MBUS_FMT_RGB332_1X8 = 0x1009,
V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001,
V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003,
@@ -46,8 +47,10 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006,
V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,
+ V4L2_MBUS_FMT_RGB24_3X8_BE = 0x100a,
+ V4L2_MBUS_FMT_RGB24_3X8_LE = 0x100b,
- /* YUV (including grey) - next is 0x2014 */
+ /* YUV (including grey) - next is 0x2015 */
V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002,
V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003,
@@ -65,10 +68,11 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_VYUY8_1X16 = 0x2010,
V4L2_MBUS_FMT_YUYV8_1X16 = 0x2011,
V4L2_MBUS_FMT_YVYU8_1X16 = 0x2012,
+ V4L2_MBUS_FMT_Y16_1X16 = 0x2014,
V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
- /* Bayer - next is 0x3015 */
+ /* Bayer - next is 0x3016 */
V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
V4L2_MBUS_FMT_SGBRG8_1X8 = 0x3013,
V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
@@ -89,6 +93,7 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_SGBRG12_1X12 = 0x3010,
V4L2_MBUS_FMT_SGRBG12_1X12 = 0x3011,
V4L2_MBUS_FMT_SRGGB12_1X12 = 0x3012,
+ V4L2_MBUS_FMT_SBGGR16_1X16 = 0x3015,
/* JPEG compressed formats - next is 0x4002 */
V4L2_MBUS_FMT_JPEG_1X8 = 0x4001,
diff --git linux-3.4.5.orig/include/media/soc_mediabus.h linux-3.4.5/include/media/soc_mediabus.h
index 73f1e7e..90a2140 100644
--- linux-3.4.5.orig/include/media/soc_mediabus.h
+++ linux-3.4.5/include/media/soc_mediabus.h
@@ -18,22 +18,46 @@
* enum soc_mbus_packing - data packing types on the media-bus
* @SOC_MBUS_PACKING_NONE: no packing, bit-for-bit transfer to RAM, one
* sample represents one pixel
+ * @SOC_MBUS_PACKING_1X8_PADHI: 8 bits transferred in 1 8-bit sample, in the
+ * possibly incomplete byte high bits are padding
+ * @SOC_MBUS_PACKING_1X8_PADLO: as above, but low bits are padding
+ * @SOC_MBUS_PACKING_EXTEND8: sample width (e.g., 4 bits) has to be extended
+ * to 8 bits
+ * @SOC_MBUS_PACKING_1_5X8: used for packed YUV 4:2:0 formats, where 4
+ * pixels occupy 6 bytes in RAM
* @SOC_MBUS_PACKING_2X8_PADHI: 16 bits transferred in 2 8-bit samples, in the
* possibly incomplete byte high bits are padding
* @SOC_MBUS_PACKING_2X8_PADLO: as above, but low bits are padding
* @SOC_MBUS_PACKING_EXTEND16: sample width (e.g., 10 bits) has to be extended
* to 16 bits
+ * @SOC_MBUS_PACKING_3X8_PADHI: 24 bits transferred in 3 8-bit samples, in the
+ * possibly incomplete byte high bits are padding
+ * @SOC_MBUS_PACKING_3X8_PADLO: as above, but low bits are padding
+ * @SOC_MBUS_PACKING_EXTEND24: sample width (e.g., 10 bits) has to be extended
+ * to 24 bits
+ * @SOC_MBUS_PACKING_4X8_PADHI: 32 bits transferred in 4 8-bit samples, in the
+ * possibly incomplete byte high bits are padding
+ * @SOC_MBUS_PACKING_4X8_PADLO: as above, but low bits are padding
+ * @SOC_MBUS_PACKING_EXTEND32: sample width (e.g., 10 bits) has to be extended
+ * to 32 bits
* @SOC_MBUS_PACKING_VARIABLE: compressed formats with variable packing
- * @SOC_MBUS_PACKING_1_5X8: used for packed YUV 4:2:0 formats, where 4
- * pixels occupy 6 bytes in RAM
*/
enum soc_mbus_packing {
SOC_MBUS_PACKING_NONE,
+ SOC_MBUS_PACKING_1X8_PADHI,
+ SOC_MBUS_PACKING_1X8_PADLO,
+ SOC_MBUS_PACKING_EXTEND8,
+ SOC_MBUS_PACKING_1_5X8,
SOC_MBUS_PACKING_2X8_PADHI,
SOC_MBUS_PACKING_2X8_PADLO,
SOC_MBUS_PACKING_EXTEND16,
+ SOC_MBUS_PACKING_3X8_PADHI,
+ SOC_MBUS_PACKING_3X8_PADLO,
+ SOC_MBUS_PACKING_EXTEND24,
+ SOC_MBUS_PACKING_4X8_PADHI,
+ SOC_MBUS_PACKING_4X8_PADLO,
+ SOC_MBUS_PACKING_EXTEND32,
SOC_MBUS_PACKING_VARIABLE,
- SOC_MBUS_PACKING_1_5X8,
};
/**
^ permalink raw reply related
* [PATCH 11/11] nand: Increase the ecc placement locations to 640
From: Artem Bityutskiy @ 2012-10-17 12:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <67e0aae3b23f37feb30789f5c6cb342b5684911a.1349778821.git.vipin.kumar@st.com>
On Tue, 2012-10-09 at 16:14 +0530, Vipin Kumar wrote:
> Few devices like H27UBG8T2CTR have a writesize/oobsize of 8KB/640B.
> This means that the maximum oobsize has gone up to 640 bytes and consequently
> the maximum ecc placement locations have also gone up to 640.
>
> Signed-off-by: Vipin Kumar <vipin.kumar@st.com>
Pushed this one to l2-mtd.git, thanks!
--
Best Regards,
Artem Bityutskiy
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121017/508f73cf/attachment.sig>
^ permalink raw reply
* [PATCH 06/11] fsmc/nand: Modify the wait to uninterruptible
From: Artem Bityutskiy @ 2012-10-17 12:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3dcb002d0ad03dde9a91e8128dbaa320b8a264a9.1349778821.git.vipin.kumar@st.com>
On Tue, 2012-10-09 at 16:14 +0530, Vipin Kumar wrote:
> Interruptible wait caused trouble in fsmc hardware state machine if the
> application was killed abruptly. To make fsmc operation safe turn wait in to
> un-interruptible.
>
> Signed-off-by: Vipin Kumar <vipin.kumar@st.com>
Pushed this one to l2-mtd.git, thanks!
--
Best Regards,
Artem Bityutskiy
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121017/59249ec7/attachment-0001.sig>
^ permalink raw reply
* [PATCH 00/11] mtd/nand: fsmc driver updates
From: Artem Bityutskiy @ 2012-10-17 12:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1349778820.git.vipin.kumar@st.com>
On Tue, 2012-10-09 at 16:14 +0530, Vipin Kumar wrote:
> This patch-set contains several fixes and a few enhancements in fsmc driver.
> Modifications include
OK, picked some patches from your series, some do not apply. Please,
send v2 against the l2-mtd.git tree:
git://git.infradead.org/users/dedekind/l2-mtd.git
Thanks!
--
Best Regards,
Artem Bityutskiy
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121017/d73a2a7b/attachment.sig>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox