1 /* 2 * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> 3 * 4 * Original author: 5 * Ben Collins <bcollins@ubuntu.com> 6 * 7 * Additional work by: 8 * John Brooks <john.brooks@bluecherry.net> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21 #include <linux/kernel.h> 22 #include <linux/fs.h> 23 #include <linux/delay.h> 24 #include <linux/uaccess.h> 25 26 #include "solo6x10.h" 27 28 static void solo_gpio_mode(struct solo_dev *solo_dev, 29 unsigned int port_mask, unsigned int mode) 30 { 31 int port; 32 unsigned int ret; 33 34 ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0); 35 36 /* To set gpio */ 37 for (port = 0; port < 16; port++) { 38 if (!((1 << port) & port_mask)) 39 continue; 40 41 ret &= (~(3 << (port << 1))); 42 ret |= ((mode & 3) << (port << 1)); 43 } 44 45 solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret); 46 47 /* To set extended gpio - sensor */ 48 ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1); 49 50 for (port = 0; port < 16; port++) { 51 if (!((1 << (port + 16)) & port_mask)) 52 continue; 53 54 if (!mode) 55 ret &= ~(1 << port); 56 else 57 ret |= 1 << port; 58 } 59 60 /* Enable GPIO[31:16] */ 61 ret |= 0xffff0000; 62 63 solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret); 64 } 65 66 static void solo_gpio_set(struct solo_dev *solo_dev, unsigned int value) 67 { 68 solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT, 69 solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value); 70 } 71 72 static void solo_gpio_clear(struct solo_dev *solo_dev, unsigned int value) 73 { 74 solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT, 75 solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value); 76 } 77 78 static void solo_gpio_config(struct solo_dev *solo_dev) 79 { 80 /* Video reset */ 81 solo_gpio_mode(solo_dev, 0x30, 1); 82 solo_gpio_clear(solo_dev, 0x30); 83 udelay(100); 84 solo_gpio_set(solo_dev, 0x30); 85 udelay(100); 86 87 /* Warning: Don't touch the next line unless you're sure of what 88 * you're doing: first four gpio [0-3] are used for video. */ 89 solo_gpio_mode(solo_dev, 0x0f, 2); 90 91 /* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */ 92 solo_gpio_mode(solo_dev, 0xff00, 1); 93 94 /* Initially set relay status to 0 */ 95 solo_gpio_clear(solo_dev, 0xff00); 96 97 /* Set input pins direction */ 98 solo_gpio_mode(solo_dev, 0xffff0000, 0); 99 } 100 101 #ifdef CONFIG_GPIOLIB 102 /* Pins 0-7 are not exported, because it seems from code above they are 103 * used for internal purposes. So offset 0 corresponds to pin 8, therefore 104 * offsets 0-7 are relay GPIOs, 8-23 - input GPIOs. 105 */ 106 static int solo_gpiochip_get_direction(struct gpio_chip *chip, 107 unsigned int offset) 108 { 109 int ret, mode; 110 struct solo_dev *solo_dev = gpiochip_get_data(chip); 111 112 if (offset < 8) { 113 ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0); 114 mode = 3 & (ret >> ((offset + 8) * 2)); 115 } else { 116 ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1); 117 mode = 1 & (ret >> (offset - 8)); 118 } 119 120 if (!mode) 121 return 1; 122 else if (mode == 1) 123 return 0; 124 125 return -1; 126 } 127 128 static int solo_gpiochip_direction_input(struct gpio_chip *chip, 129 unsigned int offset) 130 { 131 return -1; 132 } 133 134 static int solo_gpiochip_direction_output(struct gpio_chip *chip, 135 unsigned int offset, int value) 136 { 137 return -1; 138 } 139 140 static int solo_gpiochip_get(struct gpio_chip *chip, 141 unsigned int offset) 142 { 143 int ret; 144 struct solo_dev *solo_dev = gpiochip_get_data(chip); 145 146 ret = solo_reg_read(solo_dev, SOLO_GPIO_DATA_IN); 147 148 return 1 & (ret >> (offset + 8)); 149 } 150 151 static void solo_gpiochip_set(struct gpio_chip *chip, 152 unsigned int offset, int value) 153 { 154 struct solo_dev *solo_dev = gpiochip_get_data(chip); 155 156 if (value) 157 solo_gpio_set(solo_dev, 1 << (offset + 8)); 158 else 159 solo_gpio_clear(solo_dev, 1 << (offset + 8)); 160 } 161 #endif 162 163 int solo_gpio_init(struct solo_dev *solo_dev) 164 { 165 #ifdef CONFIG_GPIOLIB 166 int ret; 167 #endif 168 169 solo_gpio_config(solo_dev); 170 #ifdef CONFIG_GPIOLIB 171 solo_dev->gpio_dev.label = SOLO6X10_NAME"_gpio"; 172 solo_dev->gpio_dev.parent = &solo_dev->pdev->dev; 173 solo_dev->gpio_dev.owner = THIS_MODULE; 174 solo_dev->gpio_dev.base = -1; 175 solo_dev->gpio_dev.ngpio = 24; 176 solo_dev->gpio_dev.can_sleep = 0; 177 178 solo_dev->gpio_dev.get_direction = solo_gpiochip_get_direction; 179 solo_dev->gpio_dev.direction_input = solo_gpiochip_direction_input; 180 solo_dev->gpio_dev.direction_output = solo_gpiochip_direction_output; 181 solo_dev->gpio_dev.get = solo_gpiochip_get; 182 solo_dev->gpio_dev.set = solo_gpiochip_set; 183 184 ret = gpiochip_add_data(&solo_dev->gpio_dev, solo_dev); 185 186 if (ret) { 187 solo_dev->gpio_dev.label = NULL; 188 return -1; 189 } 190 #endif 191 return 0; 192 } 193 194 void solo_gpio_exit(struct solo_dev *solo_dev) 195 { 196 #ifdef CONFIG_GPIOLIB 197 if (solo_dev->gpio_dev.label) { 198 gpiochip_remove(&solo_dev->gpio_dev); 199 solo_dev->gpio_dev.label = NULL; 200 } 201 #endif 202 solo_gpio_clear(solo_dev, 0x30); 203 solo_gpio_config(solo_dev); 204 } 205