Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.26-rc9 263 lines 6.2 kB view raw
1/* 2 * Core driver for HTC PASIC3 LED/DS1WM chip. 3 * 4 * Copyright (C) 2006 Philipp Zabel <philipp.zabel@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License. 9 */ 10 11#include <linux/init.h> 12#include <linux/module.h> 13#include <linux/platform_device.h> 14 15#include <linux/ds1wm.h> 16#include <linux/gpio.h> 17#include <linux/io.h> 18#include <linux/irq.h> 19#include <linux/interrupt.h> 20#include <linux/mfd/htc-pasic3.h> 21 22struct pasic3_data { 23 void __iomem *mapping; 24 unsigned int bus_shift; 25 struct platform_device *ds1wm_pdev; 26 struct platform_device *led_pdev; 27}; 28 29#define REG_ADDR 5 30#define REG_DATA 6 31 32#define READ_MODE 0x80 33 34/* 35 * write to a secondary register on the PASIC3 36 */ 37void pasic3_write_register(struct device *dev, u32 reg, u8 val) 38{ 39 struct pasic3_data *asic = dev->driver_data; 40 int bus_shift = asic->bus_shift; 41 void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift); 42 void __iomem *data = asic->mapping + (REG_DATA << bus_shift); 43 44 __raw_writeb(~READ_MODE & reg, addr); 45 __raw_writeb(val, data); 46} 47EXPORT_SYMBOL(pasic3_write_register); /* for leds-pasic3 */ 48 49/* 50 * read from a secondary register on the PASIC3 51 */ 52u8 pasic3_read_register(struct device *dev, u32 reg) 53{ 54 struct pasic3_data *asic = dev->driver_data; 55 int bus_shift = asic->bus_shift; 56 void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift); 57 void __iomem *data = asic->mapping + (REG_DATA << bus_shift); 58 59 __raw_writeb(READ_MODE | reg, addr); 60 return __raw_readb(data); 61} 62EXPORT_SYMBOL(pasic3_read_register); /* for leds-pasic3 */ 63 64/* 65 * LEDs 66 */ 67 68static int led_device_add(struct device *pasic3_dev, 69 const struct pasic3_leds_machinfo *pdata) 70{ 71 struct pasic3_data *asic = pasic3_dev->driver_data; 72 struct platform_device *pdev; 73 int ret; 74 75 pdev = platform_device_alloc("pasic3-led", -1); 76 if (!pdev) { 77 dev_dbg(pasic3_dev, "failed to allocate LED platform device\n"); 78 return -ENOMEM; 79 } 80 81 ret = platform_device_add_data(pdev, pdata, 82 sizeof(struct pasic3_leds_machinfo)); 83 if (ret < 0) { 84 dev_dbg(pasic3_dev, "failed to add LED platform data\n"); 85 goto exit_pdev_put; 86 } 87 88 pdev->dev.parent = pasic3_dev; 89 ret = platform_device_add(pdev); 90 if (ret < 0) { 91 dev_dbg(pasic3_dev, "failed to add LED platform device\n"); 92 goto exit_pdev_put; 93 } 94 95 asic->led_pdev = pdev; 96 return 0; 97 98exit_pdev_put: 99 platform_device_put(pdev); 100 return ret; 101} 102 103/* 104 * DS1WM 105 */ 106 107static void ds1wm_enable(struct platform_device *pdev) 108{ 109 struct device *dev = pdev->dev.parent; 110 int c; 111 112 c = pasic3_read_register(dev, 0x28); 113 pasic3_write_register(dev, 0x28, c & 0x7f); 114 115 dev_dbg(dev, "DS1WM OWM_EN low (active) %02x\n", c & 0x7f); 116} 117 118static void ds1wm_disable(struct platform_device *pdev) 119{ 120 struct device *dev = pdev->dev.parent; 121 int c; 122 123 c = pasic3_read_register(dev, 0x28); 124 pasic3_write_register(dev, 0x28, c | 0x80); 125 126 dev_dbg(dev, "DS1WM OWM_EN high (inactive) %02x\n", c | 0x80); 127} 128 129static struct ds1wm_platform_data ds1wm_pdata = { 130 .bus_shift = 2, 131 .enable = ds1wm_enable, 132 .disable = ds1wm_disable, 133}; 134 135static int ds1wm_device_add(struct platform_device *pasic3_pdev, int bus_shift) 136{ 137 struct device *pasic3_dev = &pasic3_pdev->dev; 138 struct pasic3_data *asic = pasic3_dev->driver_data; 139 struct platform_device *pdev; 140 int ret; 141 142 pdev = platform_device_alloc("ds1wm", -1); 143 if (!pdev) { 144 dev_dbg(pasic3_dev, "failed to allocate DS1WM platform device\n"); 145 return -ENOMEM; 146 } 147 148 ret = platform_device_add_resources(pdev, pasic3_pdev->resource, 149 pasic3_pdev->num_resources); 150 if (ret < 0) { 151 dev_dbg(pasic3_dev, "failed to add DS1WM resources\n"); 152 goto exit_pdev_put; 153 } 154 155 ds1wm_pdata.bus_shift = asic->bus_shift; 156 ret = platform_device_add_data(pdev, &ds1wm_pdata, 157 sizeof(struct ds1wm_platform_data)); 158 if (ret < 0) { 159 dev_dbg(pasic3_dev, "failed to add DS1WM platform data\n"); 160 goto exit_pdev_put; 161 } 162 163 pdev->dev.parent = pasic3_dev; 164 ret = platform_device_add(pdev); 165 if (ret < 0) { 166 dev_dbg(pasic3_dev, "failed to add DS1WM platform device\n"); 167 goto exit_pdev_put; 168 } 169 170 asic->ds1wm_pdev = pdev; 171 return 0; 172 173exit_pdev_put: 174 platform_device_put(pdev); 175 return ret; 176} 177 178static int __init pasic3_probe(struct platform_device *pdev) 179{ 180 struct pasic3_platform_data *pdata = pdev->dev.platform_data; 181 struct device *dev = &pdev->dev; 182 struct pasic3_data *asic; 183 struct resource *r; 184 int ret; 185 186 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 187 if (!r) 188 return -ENXIO; 189 190 if (!request_mem_region(r->start, r->end - r->start + 1, "pasic3")) 191 return -EBUSY; 192 193 asic = kzalloc(sizeof(struct pasic3_data), GFP_KERNEL); 194 if (!asic) 195 return -ENOMEM; 196 197 platform_set_drvdata(pdev, asic); 198 199 if (pdata && pdata->bus_shift) 200 asic->bus_shift = pdata->bus_shift; 201 else 202 asic->bus_shift = 2; 203 204 asic->mapping = ioremap(r->start, r->end - r->start + 1); 205 if (!asic->mapping) { 206 dev_err(dev, "couldn't ioremap PASIC3\n"); 207 kfree(asic); 208 return -ENOMEM; 209 } 210 211 ret = ds1wm_device_add(pdev, asic->bus_shift); 212 if (ret < 0) 213 dev_warn(dev, "failed to register DS1WM\n"); 214 215 if (pdata->led_pdata) { 216 ret = led_device_add(dev, pdata->led_pdata); 217 if (ret < 0) 218 dev_warn(dev, "failed to register LED device\n"); 219 } 220 221 return 0; 222} 223 224static int pasic3_remove(struct platform_device *pdev) 225{ 226 struct pasic3_data *asic = platform_get_drvdata(pdev); 227 struct resource *r; 228 229 if (asic->led_pdev) 230 platform_device_unregister(asic->led_pdev); 231 if (asic->ds1wm_pdev) 232 platform_device_unregister(asic->ds1wm_pdev); 233 234 iounmap(asic->mapping); 235 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 236 release_mem_region(r->start, r->end - r->start + 1); 237 kfree(asic); 238 return 0; 239} 240 241static struct platform_driver pasic3_driver = { 242 .driver = { 243 .name = "pasic3", 244 }, 245 .remove = pasic3_remove, 246}; 247 248static int __init pasic3_base_init(void) 249{ 250 return platform_driver_probe(&pasic3_driver, pasic3_probe); 251} 252 253static void __exit pasic3_base_exit(void) 254{ 255 platform_driver_unregister(&pasic3_driver); 256} 257 258module_init(pasic3_base_init); 259module_exit(pasic3_base_exit); 260 261MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>"); 262MODULE_DESCRIPTION("Core driver for HTC PASIC3"); 263MODULE_LICENSE("GPL");