Commit 6048a3dd2371c58611ea0ab8b306f8f1469399ae

Authored by Cory Maccarrone
Committed by Samuel Ortiz
1 parent 08ff6f2a99

mfd: Add HTCPLD driver

This change introduces a driver for the HTC PLD chip found
on some smartphones, such as the HTC Wizard and HTC Herald.
It works through the I2C bus and acts as a GPIO extender.
Specifically:

 * it can have several sub-devices, each with its own I2C
   address
 * Each sub-device provides 8 output and 8 input pins
 * The chip attaches to one GPIO to signal when any of the
   input GPIOs change -- at which point all chips must be
   scanned for changes

This driver implements the GPIOs throught the kernel's
GPIO and IRQ framework.  This allows any GPIO-servicing
drivers to operate on htcpld pins, such as the gpio-keys
and gpio-leds drivers.

Signed-off-by: Cory Maccarrone <darkstar6262@gmail.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

Showing 4 changed files with 744 additions and 0 deletions Side-by-side Diff

... ... @@ -78,6 +78,15 @@
78 78 HTC Magician devices, respectively. Actual functionality is
79 79 handled by the leds-pasic3 and ds1wm drivers.
80 80  
  81 +config HTC_I2CPLD
  82 + bool "HTC I2C PLD chip support"
  83 + depends on I2C=y
  84 + help
  85 + If you say yes here you get support for the supposed CPLD
  86 + found on omap850 HTC devices like the HTC Wizard and HTC Herald.
  87 + This device provides input and output GPIOs through an I2C
  88 + interface to one or more sub-chips.
  89 +
81 90 config UCB1400_CORE
82 91 tristate "Philips UCB1400 Core driver"
83 92 depends on AC97_BUS
drivers/mfd/Makefile
... ... @@ -10,6 +10,7 @@
10 10  
11 11 obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
12 12 obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
  13 +obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
13 14  
14 15 obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
15 16  
drivers/mfd/htc-i2cpld.c
  1 +/*
  2 + * htc-i2cpld.c
  3 + * Chip driver for an unknown CPLD chip found on omap850 HTC devices like
  4 + * the HTC Wizard and HTC Herald.
  5 + * The cpld is located on the i2c bus and acts as an input/output GPIO
  6 + * extender.
  7 + *
  8 + * Copyright (C) 2009 Cory Maccarrone <darkstar6262@gmail.com>
  9 + *
  10 + * Based on work done in the linwizard project
  11 + * Copyright (C) 2008-2009 Angelo Arrifano <miknix@gmail.com>
  12 + *
  13 + * This program is free software; you can redistribute it and/or modify
  14 + * it under the terms of the GNU General Public License as published by
  15 + * the Free Software Foundation; either version 2 of the License, or
  16 + * (at your option) any later version.
  17 + *
  18 + * This program is distributed in the hope that it will be useful,
  19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21 + * GNU General Public License for more details.
  22 + *
  23 + * You should have received a copy of the GNU General Public License
  24 + * along with this program; if not, write to the Free Software
  25 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26 + */
  27 +
  28 +#include <linux/kernel.h>
  29 +#include <linux/init.h>
  30 +#include <linux/module.h>
  31 +#include <linux/interrupt.h>
  32 +#include <linux/platform_device.h>
  33 +#include <linux/i2c.h>
  34 +#include <linux/irq.h>
  35 +#include <linux/spinlock.h>
  36 +#include <linux/htcpld.h>
  37 +#include <linux/gpio.h>
  38 +
  39 +struct htcpld_chip {
  40 + spinlock_t lock;
  41 +
  42 + /* chip info */
  43 + u8 reset;
  44 + u8 addr;
  45 + struct device *dev;
  46 + struct i2c_client *client;
  47 +
  48 + /* Output details */
  49 + u8 cache_out;
  50 + struct gpio_chip chip_out;
  51 +
  52 + /* Input details */
  53 + u8 cache_in;
  54 + struct gpio_chip chip_in;
  55 +
  56 + u16 irqs_enabled;
  57 + uint irq_start;
  58 + int nirqs;
  59 +
  60 + /*
  61 + * Work structure to allow for setting values outside of any
  62 + * possible interrupt context
  63 + */
  64 + struct work_struct set_val_work;
  65 +};
  66 +
  67 +struct htcpld_data {
  68 + /* irq info */
  69 + u16 irqs_enabled;
  70 + uint irq_start;
  71 + int nirqs;
  72 + uint chained_irq;
  73 + unsigned int int_reset_gpio_hi;
  74 + unsigned int int_reset_gpio_lo;
  75 +
  76 + /* htcpld info */
  77 + struct htcpld_chip *chip;
  78 + unsigned int nchips;
  79 +};
  80 +
  81 +/* There does not appear to be a way to proactively mask interrupts
  82 + * on the htcpld chip itself. So, we simply ignore interrupts that
  83 + * aren't desired. */
  84 +static void htcpld_mask(unsigned int irq)
  85 +{
  86 + struct htcpld_chip *chip = get_irq_chip_data(irq);
  87 + chip->irqs_enabled &= ~(1 << (irq - chip->irq_start));
  88 + pr_debug("HTCPLD mask %d %04x\n", irq, chip->irqs_enabled);
  89 +}
  90 +static void htcpld_unmask(unsigned int irq)
  91 +{
  92 + struct htcpld_chip *chip = get_irq_chip_data(irq);
  93 + chip->irqs_enabled |= 1 << (irq - chip->irq_start);
  94 + pr_debug("HTCPLD unmask %d %04x\n", irq, chip->irqs_enabled);
  95 +}
  96 +
  97 +static int htcpld_set_type(unsigned int irq, unsigned int flags)
  98 +{
  99 + struct irq_desc *d = irq_to_desc(irq);
  100 +
  101 + if (!d) {
  102 + pr_err("HTCPLD invalid IRQ: %d\n", irq);
  103 + return -EINVAL;
  104 + }
  105 +
  106 + if (flags & ~IRQ_TYPE_SENSE_MASK)
  107 + return -EINVAL;
  108 +
  109 + /* We only allow edge triggering */
  110 + if (flags & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))
  111 + return -EINVAL;
  112 +
  113 + d->status &= ~IRQ_TYPE_SENSE_MASK;
  114 + d->status |= flags;
  115 +
  116 + return 0;
  117 +}
  118 +
  119 +static struct irq_chip htcpld_muxed_chip = {
  120 + .name = "htcpld",
  121 + .mask = htcpld_mask,
  122 + .unmask = htcpld_unmask,
  123 + .set_type = htcpld_set_type,
  124 +};
  125 +
  126 +/* To properly dispatch IRQ events, we need to read from the
  127 + * chip. This is an I2C action that could possibly sleep
  128 + * (which is bad in interrupt context) -- so we use a threaded
  129 + * interrupt handler to get around that.
  130 + */
  131 +static irqreturn_t htcpld_handler(int irq, void *dev)
  132 +{
  133 + struct htcpld_data *htcpld = dev;
  134 + unsigned int i;
  135 + unsigned long flags;
  136 + int irqpin;
  137 + struct irq_desc *desc;
  138 +
  139 + if (!htcpld) {
  140 + pr_debug("htcpld is null in ISR\n");
  141 + return IRQ_HANDLED;
  142 + }
  143 +
  144 + /*
  145 + * For each chip, do a read of the chip and trigger any interrupts
  146 + * desired. The interrupts will be triggered from LSB to MSB (i.e.
  147 + * bit 0 first, then bit 1, etc.)
  148 + *
  149 + * For chips that have no interrupt range specified, just skip 'em.
  150 + */
  151 + for (i = 0; i < htcpld->nchips; i++) {
  152 + struct htcpld_chip *chip = &htcpld->chip[i];
  153 + struct i2c_client *client;
  154 + int val;
  155 + unsigned long uval, old_val;
  156 +
  157 + if (!chip) {
  158 + pr_debug("chip %d is null in ISR\n", i);
  159 + continue;
  160 + }
  161 +
  162 + if (chip->nirqs == 0)
  163 + continue;
  164 +
  165 + client = chip->client;
  166 + if (!client) {
  167 + pr_debug("client %d is null in ISR\n", i);
  168 + continue;
  169 + }
  170 +
  171 + /* Scan the chip */
  172 + val = i2c_smbus_read_byte_data(client, chip->cache_out);
  173 + if (val < 0) {
  174 + /* Throw a warning and skip this chip */
  175 + dev_warn(chip->dev, "Unable to read from chip: %d\n",
  176 + val);
  177 + continue;
  178 + }
  179 +
  180 + uval = (unsigned long)val;
  181 +
  182 + spin_lock_irqsave(&chip->lock, flags);
  183 +
  184 + /* Save away the old value so we can compare it */
  185 + old_val = chip->cache_in;
  186 +
  187 + /* Write the new value */
  188 + chip->cache_in = uval;
  189 +
  190 + spin_unlock_irqrestore(&chip->lock, flags);
  191 +
  192 + /*
  193 + * For each bit in the data (starting at bit 0), trigger
  194 + * associated interrupts.
  195 + */
  196 + for (irqpin = 0; irqpin < chip->nirqs; irqpin++) {
  197 + unsigned oldb, newb;
  198 + int flags;
  199 +
  200 + irq = chip->irq_start + irqpin;
  201 + desc = irq_to_desc(irq);
  202 + flags = desc->status;
  203 +
  204 + /* Run the IRQ handler, but only if the bit value
  205 + * changed, and the proper flags are set */
  206 + oldb = (old_val >> irqpin) & 1;
  207 + newb = (uval >> irqpin) & 1;
  208 +
  209 + if ((!oldb && newb && (flags & IRQ_TYPE_EDGE_RISING)) ||
  210 + (oldb && !newb &&
  211 + (flags & IRQ_TYPE_EDGE_FALLING))) {
  212 + pr_debug("fire IRQ %d\n", irqpin);
  213 + desc->handle_irq(irq, desc);
  214 + }
  215 + }
  216 + }
  217 +
  218 + /*
  219 + * In order to continue receiving interrupts, the int_reset_gpio must
  220 + * be asserted.
  221 + */
  222 + if (htcpld->int_reset_gpio_hi)
  223 + gpio_set_value(htcpld->int_reset_gpio_hi, 1);
  224 + if (htcpld->int_reset_gpio_lo)
  225 + gpio_set_value(htcpld->int_reset_gpio_lo, 0);
  226 +
  227 + return IRQ_HANDLED;
  228 +}
  229 +
  230 +/*
  231 + * The GPIO set routines can be called from interrupt context, especially if,
  232 + * for example they're attached to the led-gpio framework and a trigger is
  233 + * enabled. As such, we declared work above in the htcpld_chip structure,
  234 + * and that work is scheduled in the set routine. The kernel can then run
  235 + * the I2C functions, which will sleep, in process context.
  236 + */
  237 +void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
  238 +{
  239 + struct i2c_client *client;
  240 + struct htcpld_chip *chip_data;
  241 + unsigned long flags;
  242 +
  243 + chip_data = container_of(chip, struct htcpld_chip, chip_out);
  244 + if (!chip_data)
  245 + return;
  246 +
  247 + client = chip_data->client;
  248 + if (client == NULL)
  249 + return;
  250 +
  251 + spin_lock_irqsave(&chip_data->lock, flags);
  252 + if (val)
  253 + chip_data->cache_out |= (1 << offset);
  254 + else
  255 + chip_data->cache_out &= ~(1 << offset);
  256 + spin_unlock_irqrestore(&chip_data->lock, flags);
  257 +
  258 + schedule_work(&(chip_data->set_val_work));
  259 +}
  260 +
  261 +void htcpld_chip_set_ni(struct work_struct *work)
  262 +{
  263 + struct htcpld_chip *chip_data;
  264 + struct i2c_client *client;
  265 +
  266 + chip_data = container_of(work, struct htcpld_chip, set_val_work);
  267 + client = chip_data->client;
  268 + i2c_smbus_read_byte_data(client, chip_data->cache_out);
  269 +}
  270 +
  271 +int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
  272 +{
  273 + struct htcpld_chip *chip_data;
  274 + int val = 0;
  275 + int is_input = 0;
  276 +
  277 + /* Try out first */
  278 + chip_data = container_of(chip, struct htcpld_chip, chip_out);
  279 + if (!chip_data) {
  280 + /* Try in */
  281 + is_input = 1;
  282 + chip_data = container_of(chip, struct htcpld_chip, chip_in);
  283 + if (!chip_data)
  284 + return -EINVAL;
  285 + }
  286 +
  287 + /* Determine if this is an input or output GPIO */
  288 + if (!is_input)
  289 + /* Use the output cache */
  290 + val = (chip_data->cache_out >> offset) & 1;
  291 + else
  292 + /* Use the input cache */
  293 + val = (chip_data->cache_in >> offset) & 1;
  294 +
  295 + if (val)
  296 + return 1;
  297 + else
  298 + return 0;
  299 +}
  300 +
  301 +static int htcpld_direction_output(struct gpio_chip *chip,
  302 + unsigned offset, int value)
  303 +{
  304 + htcpld_chip_set(chip, offset, value);
  305 + return 0;
  306 +}
  307 +
  308 +static int htcpld_direction_input(struct gpio_chip *chip,
  309 + unsigned offset)
  310 +{
  311 + /*
  312 + * No-op: this function can only be called on the input chip.
  313 + * We do however make sure the offset is within range.
  314 + */
  315 + return (offset < chip->ngpio) ? 0 : -EINVAL;
  316 +}
  317 +
  318 +int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
  319 +{
  320 + struct htcpld_chip *chip_data;
  321 +
  322 + chip_data = container_of(chip, struct htcpld_chip, chip_in);
  323 +
  324 + if (offset < chip_data->nirqs)
  325 + return chip_data->irq_start + offset;
  326 + else
  327 + return -EINVAL;
  328 +}
  329 +
  330 +void htcpld_chip_reset(struct i2c_client *client)
  331 +{
  332 + struct htcpld_chip *chip_data = i2c_get_clientdata(client);
  333 + if (!chip_data)
  334 + return;
  335 +
  336 + i2c_smbus_read_byte_data(
  337 + client, (chip_data->cache_out = chip_data->reset));
  338 +}
  339 +
  340 +static int __devinit htcpld_setup_chip_irq(
  341 + struct platform_device *pdev,
  342 + int chip_index)
  343 +{
  344 + struct htcpld_data *htcpld;
  345 + struct device *dev = &pdev->dev;
  346 + struct htcpld_core_platform_data *pdata;
  347 + struct htcpld_chip *chip;
  348 + struct htcpld_chip_platform_data *plat_chip_data;
  349 + unsigned int irq, irq_end;
  350 + int ret = 0;
  351 +
  352 + /* Get the platform and driver data */
  353 + pdata = dev->platform_data;
  354 + htcpld = platform_get_drvdata(pdev);
  355 + chip = &htcpld->chip[chip_index];
  356 + plat_chip_data = &pdata->chip[chip_index];
  357 +
  358 + /* Setup irq handlers */
  359 + irq_end = chip->irq_start + chip->nirqs;
  360 + for (irq = chip->irq_start; irq < irq_end; irq++) {
  361 + set_irq_chip(irq, &htcpld_muxed_chip);
  362 + set_irq_chip_data(irq, chip);
  363 + set_irq_handler(irq, handle_simple_irq);
  364 +#ifdef CONFIG_ARM
  365 + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
  366 +#else
  367 + set_irq_probe(irq);
  368 +#endif
  369 + }
  370 +
  371 + return ret;
  372 +}
  373 +
  374 +static int __devinit htcpld_register_chip_i2c(
  375 + struct platform_device *pdev,
  376 + int chip_index)
  377 +{
  378 + struct htcpld_data *htcpld;
  379 + struct device *dev = &pdev->dev;
  380 + struct htcpld_core_platform_data *pdata;
  381 + struct htcpld_chip *chip;
  382 + struct htcpld_chip_platform_data *plat_chip_data;
  383 + struct i2c_adapter *adapter;
  384 + struct i2c_client *client;
  385 + struct i2c_board_info info;
  386 +
  387 + /* Get the platform and driver data */
  388 + pdata = dev->platform_data;
  389 + htcpld = platform_get_drvdata(pdev);
  390 + chip = &htcpld->chip[chip_index];
  391 + plat_chip_data = &pdata->chip[chip_index];
  392 +
  393 + adapter = i2c_get_adapter(pdata->i2c_adapter_id);
  394 + if (adapter == NULL) {
  395 + /* Eek, no such I2C adapter! Bail out. */
  396 + dev_warn(dev, "Chip at i2c address 0x%x: Invalid i2c adapter %d\n",
  397 + plat_chip_data->addr, pdata->i2c_adapter_id);
  398 + return -ENODEV;
  399 + }
  400 +
  401 + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
  402 + dev_warn(dev, "i2c adapter %d non-functional\n",
  403 + pdata->i2c_adapter_id);
  404 + return -EINVAL;
  405 + }
  406 +
  407 + memset(&info, 0, sizeof(struct i2c_board_info));
  408 + info.addr = plat_chip_data->addr;
  409 + strlcpy(info.type, "htcpld-chip", I2C_NAME_SIZE);
  410 + info.platform_data = chip;
  411 +
  412 + /* Add the I2C device. This calls the probe() function. */
  413 + client = i2c_new_device(adapter, &info);
  414 + if (!client) {
  415 + /* I2C device registration failed, contineu with the next */
  416 + dev_warn(dev, "Unable to add I2C device for 0x%x\n",
  417 + plat_chip_data->addr);
  418 + return -ENODEV;
  419 + }
  420 +
  421 + i2c_set_clientdata(client, chip);
  422 + snprintf(client->name, I2C_NAME_SIZE, "Chip_0x%d", client->addr);
  423 + chip->client = client;
  424 +
  425 + /* Reset the chip */
  426 + htcpld_chip_reset(client);
  427 + chip->cache_in = i2c_smbus_read_byte_data(client, chip->cache_out);
  428 +
  429 + return 0;
  430 +}
  431 +
  432 +static void __devinit htcpld_unregister_chip_i2c(
  433 + struct platform_device *pdev,
  434 + int chip_index)
  435 +{
  436 + struct htcpld_data *htcpld;
  437 + struct htcpld_chip *chip;
  438 +
  439 + /* Get the platform and driver data */
  440 + htcpld = platform_get_drvdata(pdev);
  441 + chip = &htcpld->chip[chip_index];
  442 +
  443 + if (chip->client)
  444 + i2c_unregister_device(chip->client);
  445 +}
  446 +
  447 +static int __devinit htcpld_register_chip_gpio(
  448 + struct platform_device *pdev,
  449 + int chip_index)
  450 +{
  451 + struct htcpld_data *htcpld;
  452 + struct device *dev = &pdev->dev;
  453 + struct htcpld_core_platform_data *pdata;
  454 + struct htcpld_chip *chip;
  455 + struct htcpld_chip_platform_data *plat_chip_data;
  456 + struct gpio_chip *gpio_chip;
  457 + int ret = 0;
  458 +
  459 + /* Get the platform and driver data */
  460 + pdata = dev->platform_data;
  461 + htcpld = platform_get_drvdata(pdev);
  462 + chip = &htcpld->chip[chip_index];
  463 + plat_chip_data = &pdata->chip[chip_index];
  464 +
  465 + /* Setup the GPIO chips */
  466 + gpio_chip = &(chip->chip_out);
  467 + gpio_chip->label = "htcpld-out";
  468 + gpio_chip->dev = dev;
  469 + gpio_chip->owner = THIS_MODULE;
  470 + gpio_chip->get = htcpld_chip_get;
  471 + gpio_chip->set = htcpld_chip_set;
  472 + gpio_chip->direction_input = NULL;
  473 + gpio_chip->direction_output = htcpld_direction_output;
  474 + gpio_chip->base = plat_chip_data->gpio_out_base;
  475 + gpio_chip->ngpio = plat_chip_data->num_gpios;
  476 +
  477 + gpio_chip = &(chip->chip_in);
  478 + gpio_chip->label = "htcpld-in";
  479 + gpio_chip->dev = dev;
  480 + gpio_chip->owner = THIS_MODULE;
  481 + gpio_chip->get = htcpld_chip_get;
  482 + gpio_chip->set = NULL;
  483 + gpio_chip->direction_input = htcpld_direction_input;
  484 + gpio_chip->direction_output = NULL;
  485 + gpio_chip->to_irq = htcpld_chip_to_irq;
  486 + gpio_chip->base = plat_chip_data->gpio_in_base;
  487 + gpio_chip->ngpio = plat_chip_data->num_gpios;
  488 +
  489 + /* Add the GPIO chips */
  490 + ret = gpiochip_add(&(chip->chip_out));
  491 + if (ret) {
  492 + dev_warn(dev, "Unable to register output GPIOs for 0x%x: %d\n",
  493 + plat_chip_data->addr, ret);
  494 + return ret;
  495 + }
  496 +
  497 + ret = gpiochip_add(&(chip->chip_in));
  498 + if (ret) {
  499 + int error;
  500 +
  501 + dev_warn(dev, "Unable to register input GPIOs for 0x%x: %d\n",
  502 + plat_chip_data->addr, ret);
  503 +
  504 + error = gpiochip_remove(&(chip->chip_out));
  505 + if (error)
  506 + dev_warn(dev, "Error while trying to unregister gpio chip: %d\n", error);
  507 +
  508 + return ret;
  509 + }
  510 +
  511 + return 0;
  512 +}
  513 +
  514 +static int __devinit htcpld_setup_chips(struct platform_device *pdev)
  515 +{
  516 + struct htcpld_data *htcpld;
  517 + struct device *dev = &pdev->dev;
  518 + struct htcpld_core_platform_data *pdata;
  519 + int i;
  520 +
  521 + /* Get the platform and driver data */
  522 + pdata = dev->platform_data;
  523 + htcpld = platform_get_drvdata(pdev);
  524 +
  525 + /* Setup each chip's output GPIOs */
  526 + htcpld->nchips = pdata->num_chip;
  527 + htcpld->chip = kzalloc(sizeof(struct htcpld_chip) * htcpld->nchips,
  528 + GFP_KERNEL);
  529 + if (!htcpld->chip) {
  530 + dev_warn(dev, "Unable to allocate memory for chips\n");
  531 + return -ENOMEM;
  532 + }
  533 +
  534 + /* Add the chips as best we can */
  535 + for (i = 0; i < htcpld->nchips; i++) {
  536 + int ret;
  537 +
  538 + /* Setup the HTCPLD chips */
  539 + htcpld->chip[i].reset = pdata->chip[i].reset;
  540 + htcpld->chip[i].cache_out = pdata->chip[i].reset;
  541 + htcpld->chip[i].cache_in = 0;
  542 + htcpld->chip[i].dev = dev;
  543 + htcpld->chip[i].irq_start = pdata->chip[i].irq_base;
  544 + htcpld->chip[i].nirqs = pdata->chip[i].num_irqs;
  545 +
  546 + INIT_WORK(&(htcpld->chip[i].set_val_work), &htcpld_chip_set_ni);
  547 + spin_lock_init(&(htcpld->chip[i].lock));
  548 +
  549 + /* Setup the interrupts for the chip */
  550 + if (htcpld->chained_irq) {
  551 + ret = htcpld_setup_chip_irq(pdev, i);
  552 + if (ret)
  553 + continue;
  554 + }
  555 +
  556 + /* Register the chip with I2C */
  557 + ret = htcpld_register_chip_i2c(pdev, i);
  558 + if (ret)
  559 + continue;
  560 +
  561 +
  562 + /* Register the chips with the GPIO subsystem */
  563 + ret = htcpld_register_chip_gpio(pdev, i);
  564 + if (ret) {
  565 + /* Unregister the chip from i2c and continue */
  566 + htcpld_unregister_chip_i2c(pdev, i);
  567 + continue;
  568 + }
  569 +
  570 + dev_info(dev, "Registered chip at 0x%x\n", pdata->chip[i].addr);
  571 + }
  572 +
  573 + return 0;
  574 +}
  575 +
  576 +static int __devinit htcpld_core_probe(struct platform_device *pdev)
  577 +{
  578 + struct htcpld_data *htcpld;
  579 + struct device *dev = &pdev->dev;
  580 + struct htcpld_core_platform_data *pdata;
  581 + struct resource *res;
  582 + int ret = 0;
  583 +
  584 + if (!dev)
  585 + return -ENODEV;
  586 +
  587 + pdata = dev->platform_data;
  588 + if (!pdata) {
  589 + dev_warn(dev, "Platform data not found for htcpld core!\n");
  590 + return -ENXIO;
  591 + }
  592 +
  593 + htcpld = kzalloc(sizeof(struct htcpld_data), GFP_KERNEL);
  594 + if (!htcpld)
  595 + return -ENOMEM;
  596 +
  597 + /* Find chained irq */
  598 + ret = -EINVAL;
  599 + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  600 + if (res) {
  601 + int flags;
  602 + htcpld->chained_irq = res->start;
  603 +
  604 + /* Setup the chained interrupt handler */
  605 + flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
  606 + ret = request_threaded_irq(htcpld->chained_irq,
  607 + NULL, htcpld_handler,
  608 + flags, pdev->name, htcpld);
  609 + if (ret) {
  610 + dev_warn(dev, "Unable to setup chained irq handler: %d\n", ret);
  611 + goto fail;
  612 + } else
  613 + device_init_wakeup(dev, 0);
  614 + }
  615 +
  616 + /* Set the driver data */
  617 + platform_set_drvdata(pdev, htcpld);
  618 +
  619 + /* Setup the htcpld chips */
  620 + ret = htcpld_setup_chips(pdev);
  621 + if (ret)
  622 + goto fail;
  623 +
  624 + /* Request the GPIO(s) for the int reset and set them up */
  625 + if (pdata->int_reset_gpio_hi) {
  626 + ret = gpio_request(pdata->int_reset_gpio_hi, "htcpld-core");
  627 + if (ret) {
  628 + /*
  629 + * If it failed, that sucks, but we can probably
  630 + * continue on without it.
  631 + */
  632 + dev_warn(dev, "Unable to request int_reset_gpio_hi -- interrupts may not work\n");
  633 + htcpld->int_reset_gpio_hi = 0;
  634 + } else {
  635 + htcpld->int_reset_gpio_hi = pdata->int_reset_gpio_hi;
  636 + gpio_set_value(htcpld->int_reset_gpio_hi, 1);
  637 + }
  638 + }
  639 +
  640 + if (pdata->int_reset_gpio_lo) {
  641 + ret = gpio_request(pdata->int_reset_gpio_lo, "htcpld-core");
  642 + if (ret) {
  643 + /*
  644 + * If it failed, that sucks, but we can probably
  645 + * continue on without it.
  646 + */
  647 + dev_warn(dev, "Unable to request int_reset_gpio_lo -- interrupts may not work\n");
  648 + htcpld->int_reset_gpio_lo = 0;
  649 + } else {
  650 + htcpld->int_reset_gpio_lo = pdata->int_reset_gpio_lo;
  651 + gpio_set_value(htcpld->int_reset_gpio_lo, 0);
  652 + }
  653 + }
  654 +
  655 + dev_info(dev, "Initialized successfully\n");
  656 + return 0;
  657 +
  658 +fail:
  659 + kfree(htcpld);
  660 + return ret;
  661 +}
  662 +
  663 +/* The I2C Driver -- used internally */
  664 +static const struct i2c_device_id htcpld_chip_id[] = {
  665 + { "htcpld-chip", 0 },
  666 + { }
  667 +};
  668 +MODULE_DEVICE_TABLE(i2c, htcpld_chip_id);
  669 +
  670 +
  671 +static struct i2c_driver htcpld_chip_driver = {
  672 + .driver = {
  673 + .name = "htcpld-chip",
  674 + },
  675 + .id_table = htcpld_chip_id,
  676 +};
  677 +
  678 +/* The Core Driver */
  679 +static struct platform_driver htcpld_core_driver = {
  680 + .driver = {
  681 + .name = "i2c-htcpld",
  682 + },
  683 +};
  684 +
  685 +static int __init htcpld_core_init(void)
  686 +{
  687 + int ret;
  688 +
  689 + /* Register the I2C Chip driver */
  690 + ret = i2c_add_driver(&htcpld_chip_driver);
  691 + if (ret)
  692 + return ret;
  693 +
  694 + /* Probe for our chips */
  695 + return platform_driver_probe(&htcpld_core_driver, htcpld_core_probe);
  696 +}
  697 +
  698 +static void __exit htcpld_core_exit(void)
  699 +{
  700 + i2c_del_driver(&htcpld_chip_driver);
  701 + platform_driver_unregister(&htcpld_core_driver);
  702 +}
  703 +
  704 +module_init(htcpld_core_init);
  705 +module_exit(htcpld_core_exit);
  706 +
  707 +MODULE_AUTHOR("Cory Maccarrone <darkstar6262@gmail.com>");
  708 +MODULE_DESCRIPTION("I2C HTC PLD Driver");
  709 +MODULE_LICENSE("GPL");
include/linux/htcpld.h
  1 +#ifndef __LINUX_HTCPLD_H
  2 +#define __LINUX_HTCPLD_H
  3 +
  4 +struct htcpld_chip_platform_data {
  5 + unsigned int addr;
  6 + unsigned int reset;
  7 + unsigned int num_gpios;
  8 + unsigned int gpio_out_base;
  9 + unsigned int gpio_in_base;
  10 + unsigned int irq_base;
  11 + unsigned int num_irqs;
  12 +};
  13 +
  14 +struct htcpld_core_platform_data {
  15 + unsigned int int_reset_gpio_hi;
  16 + unsigned int int_reset_gpio_lo;
  17 + unsigned int i2c_adapter_id;
  18 +
  19 + struct htcpld_chip_platform_data *chip;
  20 + unsigned int num_chip;
  21 +};
  22 +
  23 +#endif /* __LINUX_HTCPLD_H */