17ca5dc14SFlorian Fainelli /* 27ca5dc14SFlorian Fainelli * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> 37ca5dc14SFlorian Fainelli * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> 4238dd317SFlorian Fainelli * Copyright (C) 2009-2010 Florian Fainelli <florian@openwrt.org> 57ca5dc14SFlorian Fainelli * 67ca5dc14SFlorian Fainelli * This program is free software; you can redistribute it and/or modify 77ca5dc14SFlorian Fainelli * it under the terms of the GNU General Public License as published by 87ca5dc14SFlorian Fainelli * the Free Software Foundation; either version 2 of the License, or 97ca5dc14SFlorian Fainelli * (at your option) any later version. 107ca5dc14SFlorian Fainelli * 117ca5dc14SFlorian Fainelli * This program is distributed in the hope that it will be useful, 127ca5dc14SFlorian Fainelli * but WITHOUT ANY WARRANTY; without even the implied warranty of 137ca5dc14SFlorian Fainelli * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 147ca5dc14SFlorian Fainelli * GNU General Public License for more details. 157ca5dc14SFlorian Fainelli * 167ca5dc14SFlorian Fainelli * You should have received a copy of the GNU General Public License 177ca5dc14SFlorian Fainelli * along with this program; if not, write to the Free Software 187ca5dc14SFlorian Fainelli * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 197ca5dc14SFlorian Fainelli */ 207ca5dc14SFlorian Fainelli 217ca5dc14SFlorian Fainelli #include <linux/module.h> 225f3c9098SFlorian Fainelli #include <linux/gpio.h> 237ca5dc14SFlorian Fainelli 247ca5dc14SFlorian Fainelli #include <asm/mach-ar7/gpio.h> 257ca5dc14SFlorian Fainelli 265f3c9098SFlorian Fainelli struct ar7_gpio_chip { 275f3c9098SFlorian Fainelli void __iomem *regs; 285f3c9098SFlorian Fainelli struct gpio_chip chip; 295f3c9098SFlorian Fainelli }; 307ca5dc14SFlorian Fainelli 315f3c9098SFlorian Fainelli static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio) 327ca5dc14SFlorian Fainelli { 335f3c9098SFlorian Fainelli struct ar7_gpio_chip *gpch = 345f3c9098SFlorian Fainelli container_of(chip, struct ar7_gpio_chip, chip); 355f3c9098SFlorian Fainelli void __iomem *gpio_in = gpch->regs + AR7_GPIO_INPUT; 367ca5dc14SFlorian Fainelli 375f3c9098SFlorian Fainelli return readl(gpio_in) & (1 << gpio); 385f3c9098SFlorian Fainelli } 397ca5dc14SFlorian Fainelli 40238dd317SFlorian Fainelli static int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio) 41238dd317SFlorian Fainelli { 42238dd317SFlorian Fainelli struct ar7_gpio_chip *gpch = 43238dd317SFlorian Fainelli container_of(chip, struct ar7_gpio_chip, chip); 44238dd317SFlorian Fainelli void __iomem *gpio_in0 = gpch->regs + TITAN_GPIO_INPUT_0; 45238dd317SFlorian Fainelli void __iomem *gpio_in1 = gpch->regs + TITAN_GPIO_INPUT_1; 46238dd317SFlorian Fainelli 47238dd317SFlorian Fainelli return readl(gpio >> 5 ? gpio_in1 : gpio_in0) & (1 << (gpio & 0x1f)); 48238dd317SFlorian Fainelli } 49238dd317SFlorian Fainelli 505f3c9098SFlorian Fainelli static void ar7_gpio_set_value(struct gpio_chip *chip, 515f3c9098SFlorian Fainelli unsigned gpio, int value) 525f3c9098SFlorian Fainelli { 535f3c9098SFlorian Fainelli struct ar7_gpio_chip *gpch = 545f3c9098SFlorian Fainelli container_of(chip, struct ar7_gpio_chip, chip); 555f3c9098SFlorian Fainelli void __iomem *gpio_out = gpch->regs + AR7_GPIO_OUTPUT; 565f3c9098SFlorian Fainelli unsigned tmp; 575f3c9098SFlorian Fainelli 585f3c9098SFlorian Fainelli tmp = readl(gpio_out) & ~(1 << gpio); 595f3c9098SFlorian Fainelli if (value) 605f3c9098SFlorian Fainelli tmp |= 1 << gpio; 615f3c9098SFlorian Fainelli writel(tmp, gpio_out); 625f3c9098SFlorian Fainelli } 635f3c9098SFlorian Fainelli 64238dd317SFlorian Fainelli static void titan_gpio_set_value(struct gpio_chip *chip, 65238dd317SFlorian Fainelli unsigned gpio, int value) 66238dd317SFlorian Fainelli { 67238dd317SFlorian Fainelli struct ar7_gpio_chip *gpch = 68238dd317SFlorian Fainelli container_of(chip, struct ar7_gpio_chip, chip); 69238dd317SFlorian Fainelli void __iomem *gpio_out0 = gpch->regs + TITAN_GPIO_OUTPUT_0; 70238dd317SFlorian Fainelli void __iomem *gpio_out1 = gpch->regs + TITAN_GPIO_OUTPUT_1; 71238dd317SFlorian Fainelli unsigned tmp; 72238dd317SFlorian Fainelli 73238dd317SFlorian Fainelli tmp = readl(gpio >> 5 ? gpio_out1 : gpio_out0) & ~(1 << (gpio & 0x1f)); 74238dd317SFlorian Fainelli if (value) 75238dd317SFlorian Fainelli tmp |= 1 << (gpio & 0x1f); 76238dd317SFlorian Fainelli writel(tmp, gpio >> 5 ? gpio_out1 : gpio_out0); 77238dd317SFlorian Fainelli } 78238dd317SFlorian Fainelli 795f3c9098SFlorian Fainelli static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 805f3c9098SFlorian Fainelli { 815f3c9098SFlorian Fainelli struct ar7_gpio_chip *gpch = 825f3c9098SFlorian Fainelli container_of(chip, struct ar7_gpio_chip, chip); 835f3c9098SFlorian Fainelli void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; 845f3c9098SFlorian Fainelli 855f3c9098SFlorian Fainelli writel(readl(gpio_dir) | (1 << gpio), gpio_dir); 867ca5dc14SFlorian Fainelli 877ca5dc14SFlorian Fainelli return 0; 887ca5dc14SFlorian Fainelli } 897ca5dc14SFlorian Fainelli 90238dd317SFlorian Fainelli static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 91238dd317SFlorian Fainelli { 92238dd317SFlorian Fainelli struct ar7_gpio_chip *gpch = 93238dd317SFlorian Fainelli container_of(chip, struct ar7_gpio_chip, chip); 94238dd317SFlorian Fainelli void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0; 95238dd317SFlorian Fainelli void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1; 96238dd317SFlorian Fainelli 97238dd317SFlorian Fainelli if (gpio >= TITAN_GPIO_MAX) 98238dd317SFlorian Fainelli return -EINVAL; 99238dd317SFlorian Fainelli 100238dd317SFlorian Fainelli writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) | (1 << (gpio & 0x1f)), 101238dd317SFlorian Fainelli gpio >> 5 ? gpio_dir1 : gpio_dir0); 102238dd317SFlorian Fainelli return 0; 103238dd317SFlorian Fainelli } 104238dd317SFlorian Fainelli 1055f3c9098SFlorian Fainelli static int ar7_gpio_direction_output(struct gpio_chip *chip, 1065f3c9098SFlorian Fainelli unsigned gpio, int value) 1077ca5dc14SFlorian Fainelli { 1085f3c9098SFlorian Fainelli struct ar7_gpio_chip *gpch = 1095f3c9098SFlorian Fainelli container_of(chip, struct ar7_gpio_chip, chip); 1105f3c9098SFlorian Fainelli void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; 1115f3c9098SFlorian Fainelli 1125f3c9098SFlorian Fainelli ar7_gpio_set_value(chip, gpio, value); 1135f3c9098SFlorian Fainelli writel(readl(gpio_dir) & ~(1 << gpio), gpio_dir); 1145f3c9098SFlorian Fainelli 1155f3c9098SFlorian Fainelli return 0; 1167ca5dc14SFlorian Fainelli } 1175f3c9098SFlorian Fainelli 118238dd317SFlorian Fainelli static int titan_gpio_direction_output(struct gpio_chip *chip, 119238dd317SFlorian Fainelli unsigned gpio, int value) 120238dd317SFlorian Fainelli { 121238dd317SFlorian Fainelli struct ar7_gpio_chip *gpch = 122238dd317SFlorian Fainelli container_of(chip, struct ar7_gpio_chip, chip); 123238dd317SFlorian Fainelli void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0; 124238dd317SFlorian Fainelli void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1; 125238dd317SFlorian Fainelli 126238dd317SFlorian Fainelli if (gpio >= TITAN_GPIO_MAX) 127238dd317SFlorian Fainelli return -EINVAL; 128238dd317SFlorian Fainelli 129238dd317SFlorian Fainelli titan_gpio_set_value(chip, gpio, value); 130238dd317SFlorian Fainelli writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) & ~(1 << 131238dd317SFlorian Fainelli (gpio & 0x1f)), gpio >> 5 ? gpio_dir1 : gpio_dir0); 132238dd317SFlorian Fainelli 133238dd317SFlorian Fainelli return 0; 134238dd317SFlorian Fainelli } 135238dd317SFlorian Fainelli 1365f3c9098SFlorian Fainelli static struct ar7_gpio_chip ar7_gpio_chip = { 1375f3c9098SFlorian Fainelli .chip = { 1385f3c9098SFlorian Fainelli .label = "ar7-gpio", 1395f3c9098SFlorian Fainelli .direction_input = ar7_gpio_direction_input, 1405f3c9098SFlorian Fainelli .direction_output = ar7_gpio_direction_output, 1415f3c9098SFlorian Fainelli .set = ar7_gpio_set_value, 1425f3c9098SFlorian Fainelli .get = ar7_gpio_get_value, 1435f3c9098SFlorian Fainelli .base = 0, 1445f3c9098SFlorian Fainelli .ngpio = AR7_GPIO_MAX, 1455f3c9098SFlorian Fainelli } 1465f3c9098SFlorian Fainelli }; 1475f3c9098SFlorian Fainelli 148238dd317SFlorian Fainelli static struct ar7_gpio_chip titan_gpio_chip = { 149238dd317SFlorian Fainelli .chip = { 150238dd317SFlorian Fainelli .label = "titan-gpio", 151238dd317SFlorian Fainelli .direction_input = titan_gpio_direction_input, 152238dd317SFlorian Fainelli .direction_output = titan_gpio_direction_output, 153238dd317SFlorian Fainelli .set = titan_gpio_set_value, 154238dd317SFlorian Fainelli .get = titan_gpio_get_value, 155238dd317SFlorian Fainelli .base = 0, 156238dd317SFlorian Fainelli .ngpio = TITAN_GPIO_MAX, 157238dd317SFlorian Fainelli } 158238dd317SFlorian Fainelli }; 159238dd317SFlorian Fainelli 160238dd317SFlorian Fainelli static inline int ar7_gpio_enable_ar7(unsigned gpio) 1615f3c9098SFlorian Fainelli { 1625f3c9098SFlorian Fainelli void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE; 1635f3c9098SFlorian Fainelli 1645f3c9098SFlorian Fainelli writel(readl(gpio_en) | (1 << gpio), gpio_en); 1655f3c9098SFlorian Fainelli 1665f3c9098SFlorian Fainelli return 0; 1675f3c9098SFlorian Fainelli } 168238dd317SFlorian Fainelli 169238dd317SFlorian Fainelli static inline int ar7_gpio_enable_titan(unsigned gpio) 170238dd317SFlorian Fainelli { 171238dd317SFlorian Fainelli void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0; 172238dd317SFlorian Fainelli void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1; 173238dd317SFlorian Fainelli 174238dd317SFlorian Fainelli writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) | (1 << (gpio & 0x1f)), 175238dd317SFlorian Fainelli gpio >> 5 ? gpio_en1 : gpio_en0); 176238dd317SFlorian Fainelli 177238dd317SFlorian Fainelli return 0; 178238dd317SFlorian Fainelli } 179238dd317SFlorian Fainelli 180238dd317SFlorian Fainelli int ar7_gpio_enable(unsigned gpio) 181238dd317SFlorian Fainelli { 182238dd317SFlorian Fainelli return ar7_is_titan() ? ar7_gpio_enable_titan(gpio) : 183238dd317SFlorian Fainelli ar7_gpio_enable_ar7(gpio); 184238dd317SFlorian Fainelli } 1855f3c9098SFlorian Fainelli EXPORT_SYMBOL(ar7_gpio_enable); 1865f3c9098SFlorian Fainelli 187238dd317SFlorian Fainelli static inline int ar7_gpio_disable_ar7(unsigned gpio) 1885f3c9098SFlorian Fainelli { 1895f3c9098SFlorian Fainelli void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE; 1905f3c9098SFlorian Fainelli 1915f3c9098SFlorian Fainelli writel(readl(gpio_en) & ~(1 << gpio), gpio_en); 1925f3c9098SFlorian Fainelli 1935f3c9098SFlorian Fainelli return 0; 1945f3c9098SFlorian Fainelli } 195238dd317SFlorian Fainelli 196238dd317SFlorian Fainelli static inline int ar7_gpio_disable_titan(unsigned gpio) 197238dd317SFlorian Fainelli { 198238dd317SFlorian Fainelli void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0; 199238dd317SFlorian Fainelli void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1; 200238dd317SFlorian Fainelli 201238dd317SFlorian Fainelli writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) & ~(1 << (gpio & 0x1f)), 202238dd317SFlorian Fainelli gpio >> 5 ? gpio_en1 : gpio_en0); 203238dd317SFlorian Fainelli 204238dd317SFlorian Fainelli return 0; 205238dd317SFlorian Fainelli } 206238dd317SFlorian Fainelli 207238dd317SFlorian Fainelli int ar7_gpio_disable(unsigned gpio) 208238dd317SFlorian Fainelli { 209238dd317SFlorian Fainelli return ar7_is_titan() ? ar7_gpio_disable_titan(gpio) : 210238dd317SFlorian Fainelli ar7_gpio_disable_ar7(gpio); 211238dd317SFlorian Fainelli } 2125f3c9098SFlorian Fainelli EXPORT_SYMBOL(ar7_gpio_disable); 2135f3c9098SFlorian Fainelli 214238dd317SFlorian Fainelli struct titan_gpio_cfg { 215238dd317SFlorian Fainelli u32 reg; 216238dd317SFlorian Fainelli u32 shift; 217238dd317SFlorian Fainelli u32 func; 218238dd317SFlorian Fainelli }; 219238dd317SFlorian Fainelli 220edc9ded1SFlorian Fainelli static const struct titan_gpio_cfg titan_gpio_table[] = { 221238dd317SFlorian Fainelli /* reg, start bit, mux value */ 222238dd317SFlorian Fainelli {4, 24, 1}, 223238dd317SFlorian Fainelli {4, 26, 1}, 224238dd317SFlorian Fainelli {4, 28, 1}, 225238dd317SFlorian Fainelli {4, 30, 1}, 226238dd317SFlorian Fainelli {5, 6, 1}, 227238dd317SFlorian Fainelli {5, 8, 1}, 228238dd317SFlorian Fainelli {5, 10, 1}, 229238dd317SFlorian Fainelli {5, 12, 1}, 230238dd317SFlorian Fainelli {7, 14, 3}, 231238dd317SFlorian Fainelli {7, 16, 3}, 232238dd317SFlorian Fainelli {7, 18, 3}, 233238dd317SFlorian Fainelli {7, 20, 3}, 234238dd317SFlorian Fainelli {7, 22, 3}, 235238dd317SFlorian Fainelli {7, 26, 3}, 236238dd317SFlorian Fainelli {7, 28, 3}, 237238dd317SFlorian Fainelli {7, 30, 3}, 238238dd317SFlorian Fainelli {8, 0, 3}, 239238dd317SFlorian Fainelli {8, 2, 3}, 240238dd317SFlorian Fainelli {8, 4, 3}, 241238dd317SFlorian Fainelli {8, 10, 3}, 242238dd317SFlorian Fainelli {8, 14, 3}, 243238dd317SFlorian Fainelli {8, 16, 3}, 244238dd317SFlorian Fainelli {8, 18, 3}, 245238dd317SFlorian Fainelli {8, 20, 3}, 246238dd317SFlorian Fainelli {9, 8, 3}, 247238dd317SFlorian Fainelli {9, 10, 3}, 248238dd317SFlorian Fainelli {9, 12, 3}, 249238dd317SFlorian Fainelli {9, 14, 3}, 250238dd317SFlorian Fainelli {9, 18, 3}, 251238dd317SFlorian Fainelli {9, 20, 3}, 252238dd317SFlorian Fainelli {9, 24, 3}, 253238dd317SFlorian Fainelli {9, 26, 3}, 254238dd317SFlorian Fainelli {9, 28, 3}, 255238dd317SFlorian Fainelli {9, 30, 3}, 256238dd317SFlorian Fainelli {10, 0, 3}, 257238dd317SFlorian Fainelli {10, 2, 3}, 258238dd317SFlorian Fainelli {10, 8, 3}, 259238dd317SFlorian Fainelli {10, 10, 3}, 260238dd317SFlorian Fainelli {10, 12, 3}, 261238dd317SFlorian Fainelli {10, 14, 3}, 262238dd317SFlorian Fainelli {13, 12, 3}, 263238dd317SFlorian Fainelli {13, 14, 3}, 264238dd317SFlorian Fainelli {13, 16, 3}, 265238dd317SFlorian Fainelli {13, 18, 3}, 266238dd317SFlorian Fainelli {13, 24, 3}, 267238dd317SFlorian Fainelli {13, 26, 3}, 268238dd317SFlorian Fainelli {13, 28, 3}, 269238dd317SFlorian Fainelli {13, 30, 3}, 270238dd317SFlorian Fainelli {14, 2, 3}, 271238dd317SFlorian Fainelli {14, 6, 3}, 272238dd317SFlorian Fainelli {14, 8, 3}, 273238dd317SFlorian Fainelli {14, 12, 3} 274238dd317SFlorian Fainelli }; 275238dd317SFlorian Fainelli 276238dd317SFlorian Fainelli static int titan_gpio_pinsel(unsigned gpio) 277238dd317SFlorian Fainelli { 278238dd317SFlorian Fainelli struct titan_gpio_cfg gpio_cfg; 279238dd317SFlorian Fainelli u32 mux_status, pin_sel_reg, tmp; 280238dd317SFlorian Fainelli void __iomem *pin_sel = (void __iomem *)KSEG1ADDR(AR7_REGS_PINSEL); 281238dd317SFlorian Fainelli 282238dd317SFlorian Fainelli if (gpio >= ARRAY_SIZE(titan_gpio_table)) 283238dd317SFlorian Fainelli return -EINVAL; 284238dd317SFlorian Fainelli 285238dd317SFlorian Fainelli gpio_cfg = titan_gpio_table[gpio]; 286238dd317SFlorian Fainelli pin_sel_reg = gpio_cfg.reg - 1; 287238dd317SFlorian Fainelli 288238dd317SFlorian Fainelli mux_status = (readl(pin_sel + pin_sel_reg) >> gpio_cfg.shift) & 0x3; 289238dd317SFlorian Fainelli 290238dd317SFlorian Fainelli /* Check the mux status */ 291238dd317SFlorian Fainelli if (!((mux_status == 0) || (mux_status == gpio_cfg.func))) 292238dd317SFlorian Fainelli return 0; 293238dd317SFlorian Fainelli 294238dd317SFlorian Fainelli /* Set the pin sel value */ 295238dd317SFlorian Fainelli tmp = readl(pin_sel + pin_sel_reg); 296238dd317SFlorian Fainelli tmp |= ((gpio_cfg.func & 0x3) << gpio_cfg.shift); 297238dd317SFlorian Fainelli writel(tmp, pin_sel + pin_sel_reg); 298238dd317SFlorian Fainelli 299238dd317SFlorian Fainelli return 0; 300238dd317SFlorian Fainelli } 301238dd317SFlorian Fainelli 302238dd317SFlorian Fainelli /* Perform minimal Titan GPIO configuration */ 303238dd317SFlorian Fainelli static void titan_gpio_init(void) 304238dd317SFlorian Fainelli { 305238dd317SFlorian Fainelli unsigned i; 306238dd317SFlorian Fainelli 307238dd317SFlorian Fainelli for (i = 44; i < 48; i++) { 308238dd317SFlorian Fainelli titan_gpio_pinsel(i); 309238dd317SFlorian Fainelli ar7_gpio_enable_titan(i); 310238dd317SFlorian Fainelli titan_gpio_direction_input(&titan_gpio_chip.chip, i); 311238dd317SFlorian Fainelli } 312238dd317SFlorian Fainelli } 313238dd317SFlorian Fainelli 3143bc6968aSFlorian Fainelli int __init ar7_gpio_init(void) 3155f3c9098SFlorian Fainelli { 3165f3c9098SFlorian Fainelli int ret; 317238dd317SFlorian Fainelli struct ar7_gpio_chip *gpch; 318238dd317SFlorian Fainelli unsigned size; 3195f3c9098SFlorian Fainelli 320238dd317SFlorian Fainelli if (!ar7_is_titan()) { 321238dd317SFlorian Fainelli gpch = &ar7_gpio_chip; 322238dd317SFlorian Fainelli size = 0x10; 323238dd317SFlorian Fainelli } else { 324238dd317SFlorian Fainelli gpch = &titan_gpio_chip; 325238dd317SFlorian Fainelli size = 0x1f; 326238dd317SFlorian Fainelli } 327238dd317SFlorian Fainelli 3283e9957b4SFlorian Fainelli gpch->regs = ioremap_nocache(AR7_REGS_GPIO, size); 329238dd317SFlorian Fainelli if (!gpch->regs) { 330238dd317SFlorian Fainelli printk(KERN_ERR "%s: failed to ioremap regs\n", 331238dd317SFlorian Fainelli gpch->chip.label); 3325f3c9098SFlorian Fainelli return -ENOMEM; 3335f3c9098SFlorian Fainelli } 3345f3c9098SFlorian Fainelli 335238dd317SFlorian Fainelli ret = gpiochip_add(&gpch->chip); 3365f3c9098SFlorian Fainelli if (ret) { 337238dd317SFlorian Fainelli printk(KERN_ERR "%s: failed to add gpiochip\n", 338238dd317SFlorian Fainelli gpch->chip.label); 3395f3c9098SFlorian Fainelli return ret; 3405f3c9098SFlorian Fainelli } 341238dd317SFlorian Fainelli printk(KERN_INFO "%s: registered %d GPIOs\n", 342238dd317SFlorian Fainelli gpch->chip.label, gpch->chip.ngpio); 343238dd317SFlorian Fainelli 344238dd317SFlorian Fainelli if (ar7_is_titan()) 345238dd317SFlorian Fainelli titan_gpio_init(); 346238dd317SFlorian Fainelli 3475f3c9098SFlorian Fainelli return ret; 3485f3c9098SFlorian Fainelli } 349