These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpio / gpio-generic.c
index b92a690..88ae70d 100644 (file)
@@ -135,6 +135,17 @@ static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
        return 1 << (bgc->bits - 1 - pin);
 }
 
+static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct bgpio_chip *bgc = to_bgpio_chip(gc);
+       unsigned long pinmask = bgc->pin2mask(bgc, gpio);
+
+       if (bgc->dir & pinmask)
+               return !!(bgc->read_reg(bgc->reg_set) & pinmask);
+       else
+               return !!(bgc->read_reg(bgc->reg_dat) & pinmask);
+}
+
 static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
        struct bgpio_chip *bgc = to_bgpio_chip(gc);
@@ -142,6 +153,10 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
        return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio));
 }
 
+static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+}
+
 static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
        struct bgpio_chip *bgc = to_bgpio_chip(gc);
@@ -268,6 +283,12 @@ static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
        return 0;
 }
 
+static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio,
+                               int val)
+{
+       return -EINVAL;
+}
+
 static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
                                int val)
 {
@@ -291,6 +312,14 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
        return 0;
 }
 
+static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+       return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ?
+              GPIOF_DIR_OUT : GPIOF_DIR_IN;
+}
+
 static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
        struct bgpio_chip *bgc = to_bgpio_chip(gc);
@@ -340,6 +369,14 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
        return 0;
 }
 
+static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+       return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ?
+              GPIOF_DIR_IN : GPIOF_DIR_OUT;
+}
+
 static int bgpio_setup_accessors(struct device *dev,
                                 struct bgpio_chip *bgc,
                                 bool bit_be,
@@ -416,7 +453,8 @@ static int bgpio_setup_accessors(struct device *dev,
 static int bgpio_setup_io(struct bgpio_chip *bgc,
                          void __iomem *dat,
                          void __iomem *set,
-                         void __iomem *clr)
+                         void __iomem *clr,
+                         unsigned long flags)
 {
 
        bgc->reg_dat = dat;
@@ -432,19 +470,27 @@ static int bgpio_setup_io(struct bgpio_chip *bgc,
                bgc->reg_set = set;
                bgc->gc.set = bgpio_set_set;
                bgc->gc.set_multiple = bgpio_set_multiple_set;
+       } else if (flags & BGPIOF_NO_OUTPUT) {
+               bgc->gc.set = bgpio_set_none;
+               bgc->gc.set_multiple = NULL;
        } else {
                bgc->gc.set = bgpio_set;
                bgc->gc.set_multiple = bgpio_set_multiple;
        }
 
-       bgc->gc.get = bgpio_get;
+       if (!(flags & BGPIOF_UNREADABLE_REG_SET) &&
+           (flags & BGPIOF_READ_OUTPUT_REG_SET))
+               bgc->gc.get = bgpio_get_set;
+       else
+               bgc->gc.get = bgpio_get;
 
        return 0;
 }
 
 static int bgpio_setup_direction(struct bgpio_chip *bgc,
                                 void __iomem *dirout,
-                                void __iomem *dirin)
+                                void __iomem *dirin,
+                                unsigned long flags)
 {
        if (dirout && dirin) {
                return -EINVAL;
@@ -452,12 +498,17 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc,
                bgc->reg_dir = dirout;
                bgc->gc.direction_output = bgpio_dir_out;
                bgc->gc.direction_input = bgpio_dir_in;
+               bgc->gc.get_direction = bgpio_get_dir;
        } else if (dirin) {
                bgc->reg_dir = dirin;
                bgc->gc.direction_output = bgpio_dir_out_inv;
                bgc->gc.direction_input = bgpio_dir_in_inv;
+               bgc->gc.get_direction = bgpio_get_dir_inv;
        } else {
-               bgc->gc.direction_output = bgpio_simple_dir_out;
+               if (flags & BGPIOF_NO_OUTPUT)
+                       bgc->gc.direction_output = bgpio_dir_out_err;
+               else
+                       bgc->gc.direction_output = bgpio_simple_dir_out;
                bgc->gc.direction_input = bgpio_simple_dir_in;
        }
 
@@ -500,7 +551,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
        bgc->gc.ngpio = bgc->bits;
        bgc->gc.request = bgpio_request;
 
-       ret = bgpio_setup_io(bgc, dat, set, clr);
+       ret = bgpio_setup_io(bgc, dat, set, clr, flags);
        if (ret)
                return ret;
 
@@ -509,7 +560,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
        if (ret)
                return ret;
 
-       ret = bgpio_setup_direction(bgc, dirout, dirin);
+       ret = bgpio_setup_direction(bgc, dirout, dirin, flags);
        if (ret)
                return ret;
 
@@ -528,40 +579,20 @@ EXPORT_SYMBOL_GPL(bgpio_init);
 
 static void __iomem *bgpio_map(struct platform_device *pdev,
                               const char *name,
-                              resource_size_t sane_sz,
-                              int *err)
+                              resource_size_t sane_sz)
 {
-       struct device *dev = &pdev->dev;
        struct resource *r;
-       resource_size_t start;
        resource_size_t sz;
-       void __iomem *ret;
-
-       *err = 0;
 
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
        if (!r)
                return NULL;
 
        sz = resource_size(r);
-       if (sz != sane_sz) {
-               *err = -EINVAL;
-               return NULL;
-       }
-
-       start = r->start;
-       if (!devm_request_mem_region(dev, start, sz, r->name)) {
-               *err = -EBUSY;
-               return NULL;
-       }
-
-       ret = devm_ioremap(dev, start, sz);
-       if (!ret) {
-               *err = -ENOMEM;
-               return NULL;
-       }
+       if (sz != sane_sz)
+               return IOMEM_ERR_PTR(-EINVAL);
 
-       return ret;
+       return devm_ioremap_resource(&pdev->dev, r);
 }
 
 static int bgpio_pdev_probe(struct platform_device *pdev)
@@ -585,25 +616,25 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
 
        sz = resource_size(r);
 
-       dat = bgpio_map(pdev, "dat", sz, &err);
-       if (!dat)
-               return err ? err : -EINVAL;
+       dat = bgpio_map(pdev, "dat", sz);
+       if (IS_ERR(dat))
+               return PTR_ERR(dat);
 
-       set = bgpio_map(pdev, "set", sz, &err);
-       if (err)
-               return err;
+       set = bgpio_map(pdev, "set", sz);
+       if (IS_ERR(set))
+               return PTR_ERR(set);
 
-       clr = bgpio_map(pdev, "clr", sz, &err);
-       if (err)
-               return err;
+       clr = bgpio_map(pdev, "clr", sz);
+       if (IS_ERR(clr))
+               return PTR_ERR(clr);
 
-       dirout = bgpio_map(pdev, "dirout", sz, &err);
-       if (err)
-               return err;
+       dirout = bgpio_map(pdev, "dirout", sz);
+       if (IS_ERR(dirout))
+               return PTR_ERR(dirout);
 
-       dirin = bgpio_map(pdev, "dirin", sz, &err);
-       if (err)
-               return err;
+       dirin = bgpio_map(pdev, "dirin", sz);
+       if (IS_ERR(dirin))
+               return PTR_ERR(dirin);
 
        bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
        if (!bgc)