#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PCAL6416A_INPUT 0x00 /* Input port [RO] */ #define PCAL6416A_DAT_OUT 0x02 /* GPIO DATA OUT [R/W] */ #define PCAL6416A_POLARITY 0x04 /* Polarity Inversion port [R/W] */ #define PCAL6416A_CONFIG 0x06 /* Configuration port [R/W] */ #define PCAL6416A_DRIVE0 0x40 /* Output drive strength Port0 [R/W] */ #define PCAL6416A_DRIVE1 0x42 /* Output drive strength Port1 [R/W] */ #define PCAL6416A_INPUT_LATCH 0x44 /* Port0 Input latch [R/W] */ #define PCAL6416A_EN_PULLUPDOWN 0x46 /* Port0 Pull-up/Pull-down enbl [R/W] */ #define PCAL6416A_SEL_PULLUPDOWN 0x48 /* Port0 Pull-up/Pull-down slct [R/W] */ #define PCAL6416A_INT_MASK 0x4A /* Interrupt mask [R/W] */ #define PCAL6416A_INT_STATUS 0x4C /* Interrupt status [RO] */ #define PCAL6416A_OUTPUT_CONFIG 0x4F /* Output port config [R/W] */ #define PCA_GPIO_MASK 0x00FF #define PCAL64X_TYPE 0x20 //0x21 di ++ 0x20 do connect i2c-2 static const struct i2c_device_id pcal6416a_id[] = { { "pcal6416a", 16 }, { } }; MODULE_DEVICE_TABLE(i2c, pcal6416a_id); #define OF_PCA(__nrgpio, __int) (void *)(__nrgpio | PCAL64X_TYPE | __int) static const struct of_device_id pcal6416x_dt_ids[] = { { .compatible = "nxp,pcal6416a", .data = OF_PCA( 16, 0), }, { } }; MODULE_DEVICE_TABLE(of, pcal6416x_dt_ids); static const struct acpi_device_id pcal6416x_acpi_ids[] = { { "INT3491", 16 | PCAL64X_TYPE , }, { } }; MODULE_DEVICE_TABLE(acpi, pcal6416x_acpi_ids); struct pcal6416a_chip { unsigned gpio_start; uint16_t reg_output; uint16_t reg_polarity; uint16_t reg_config; uint16_t reg_drive0; uint16_t reg_drive1; uint16_t reg_inputlatch; uint16_t reg_enpullupdown; uint16_t reg_selpullupdown; uint16_t reg_intmask; uint16_t reg_outputconfig; uint16_t reg_direction; struct mutex i2c_lock; struct i2c_client *client; //struct pcal6416a_platform_data *dyn_pdata; unsigned long driver_data; struct regulator *regulator; struct gpio_chip gpio_chip; const char *const *names; }; /* write a 16-bit value to the PCAL6416A reg: register address val: the value read back from the PCAL6416A */ static int pcal6416a_write_reg(struct pcal6416a_chip *chip, int reg, uint16_t val) { int ret; printk(KERN_INFO "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ret = i2c_smbus_write_word_data(chip->client, reg, val); if (ret < 0) { dev_err(&chip->client->dev, "failed writing register\n"); return ret; } printk(KERN_INFO "DEBUG: Passed %s %d ret = %d\n",__FUNCTION__,__LINE__,ret); return 0; } /* read the 16-bit register from the PCAL6416A reg: register address val: the value read back from the PCAL6416A */ static int pcal6416a_read_reg(struct pcal6416a_chip *chip, int reg, uint16_t *val) { int ret; printk(KERN_INFO "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); ret = i2c_smbus_read_word_data(chip->client, reg); if (ret < 0) { dev_err(&chip->client->dev, "failed reading register\n"); return ret; } printk(KERN_INFO "DEBUG: Passed %s %d ret = %d\n",__FUNCTION__,__LINE__,ret); *val = (uint16_t)ret; return 0; } /* set the CONFIGURATION register of a port pin as an input off: bit number (0..15) */ static int pcal6416a_gpio_direction_input(struct gpio_chip *gc, unsigned off) { struct pcal6416a_chip *chip; uint16_t reg_val; int ret; printk(KERN_INFO "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); chip = container_of(gc, struct pcal6416a_chip, gpio_chip); reg_val = chip->reg_config | (1u << off); ret = pcal6416a_write_reg(chip, PCAL6416A_CONFIG, reg_val); if (ret) return ret; chip->reg_config = reg_val; return 0; } /* set the DIRECTION (CONFIGURATION register) of a port pin as an output off: bit number (0..15) val = 1 or 0 return: 0 if successful */ static int pcal6416a_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { struct pcal6416a_chip *chip; uint16_t reg_val; int ret; printk(KERN_INFO "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); chip = container_of(gc, struct pcal6416a_chip, gpio_chip); /* set output level */ reg_val = chip->reg_output & ~(1u << off); ret = pcal6416a_write_reg(chip, PCAL6416A_DAT_OUT, reg_val); if (ret) return ret; chip->reg_output = reg_val; /* then direction */ reg_val = chip->reg_config & ~(1u << off); ret = pcal6416a_write_reg(chip, PCAL6416A_CONFIG, reg_val); if (ret) return ret; chip->reg_config = reg_val; return 0; } /* read a port pin value (INPUT register) from the PCAL6416A off: bit number (0..15) return: bit value 0 or 1 */ static int pcal6416a_gpio_get_value(struct gpio_chip *gc, unsigned off) { struct pcal6416a_chip *chip; uint16_t reg_val; int ret; printk(KERN_INFO "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); chip = container_of(gc, struct pcal6416a_chip, gpio_chip); ret = pcal6416a_read_reg(chip, PCAL6416A_INPUT, ®_val); if (ret < 0) { /* NOTE: diagnostic already emitted; that's all we should * do unless gpio_*_value_cansleep() calls become different * from their nonsleeping siblings (and report faults). */ return 0; } return (reg_val & (1u << off)) ? 1 : 0; } /* write a port pin value (INPUT register) from the PCAL6416A off: bit number (0..15) val: 0 or 1 return: none */ static void pcal6416a_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) { struct pcal6416a_chip *chip; uint16_t reg_val; int ret; printk(KERN_INFO "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); chip = container_of(gc, struct pcal6416a_chip, gpio_chip); if (val) reg_val = chip->reg_output | (1u << off); else reg_val = chip->reg_output & ~(1u << off); ret = pcal6416a_write_reg(chip, PCAL6416A_DAT_OUT, reg_val); if (ret) return; chip->reg_output = reg_val; } static void pcal6416a_setup_gpio(struct pcal6416a_chip *chip, int gpios) { struct gpio_chip *gc; gc = &chip->gpio_chip; gc->direction_input = pcal6416a_gpio_direction_input; gc->direction_output = pcal6416a_gpio_direction_output; gc->get = pcal6416a_gpio_get_value; gc->set = pcal6416a_gpio_set_value; gc->can_sleep = 1; gc->base = chip->gpio_start; gc->ngpio = gpios; gc->label = chip->client->name; gc->parent = &chip->client->dev; gc->owner = THIS_MODULE; gc->names = chip->names; } static int pcal6416a_probe(struct i2c_client *client,const struct i2c_device_id *i2c_id) { struct pcal6416a_platform_data *pdata; struct pcal6416a_chip *chip; int ret; u32 invert = 0; struct regulator *reg; printk(KERN_INFO "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); chip = devm_kzalloc(&client->dev, sizeof(struct pcal6416a_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; pdata = dev_get_platdata(&client->dev); if (pdata) { chip->gpio_start = pdata->gpio_base; invert = pdata->invert; chip->names = pdata->names; } else { chip->gpio_start = -1; } chip->client = client; reg = devm_regulator_get(&client->dev, "vcc"); if (IS_ERR(reg)) { ret = PTR_ERR(reg); if (ret != -EPROBE_DEFER) dev_err(&client->dev, "reg get err: %d\n", ret); return ret; } ret = regulator_enable(reg); if (ret) { dev_err(&client->dev, "reg en err: %d\n", ret); return ret; } chip->regulator = reg; if (i2c_id) { chip->driver_data = i2c_id->driver_data; } else { const struct of_device_id *match; match = of_match_device(pcal6416x_dt_ids, &client->dev); if (match) { chip->driver_data = (int)(uintptr_t)match->data; } else { return ret; } } mutex_init(&chip->i2c_lock); /* * In case we have an i2c-mux controlled by a GPIO provided by an * expander using the same driver higher on the device tree, read the * i2c adapter nesting depth and use the retrieved value as lockdep * subclass for chip->i2c_lock. * * REVISIT: This solution is not complete. It protects us from lockdep * false positives when the expander controlling the i2c-mux is on * a different level on the device tree, but not when it's on the same * level on a different branch (in which case the subclass number * would be the same). * * TODO: Once a correct solution is developed, a similar fix should be * applied to all other i2c-controlled GPIO expanders (and potentially * regmap-i2c). */ lockdep_set_subclass(&chip->i2c_lock, i2c_adapter_depth(client->adapter)); /* initialize cached registers from their original values. * we can't share this chip with another i2c master. */ pcal6416a_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip); if (ret) goto err_exit; if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) dev_warn(&client->dev, "setup failed, %d\n", ret); } i2c_set_clientdata(client, chip); return 0; err_exit: regulator_disable(chip->regulator); return ret; } static int pcal6416a_remove(struct i2c_client *client) { struct pcal6416a_platform_data *pdata = client->dev.platform_data; struct pcal6416a_chip *chip = i2c_get_clientdata(client); int ret; if (pdata && pdata->teardown) { ret = pdata->teardown(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) dev_err(&client->dev, "%s failed, %d\n", "teardown", ret); } else { ret = 0; } regulator_disable(chip->regulator); return ret; } static struct i2c_driver pcal6416a_driver = { .driver = { .name = "pcal6416a", }, .probe = pcal6416a_probe, .remove = pcal6416a_remove, .id_table = pcal6416a_id, }; static int __init pcal6416a_init(void) { printk(KERN_INFO "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); return i2c_add_driver(&pcal6416a_driver); printk(KERN_INFO "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); } /* register after i2c postcore initcall and before * subsys initcalls that may rely on these GPIOs */ subsys_initcall(pcal6416a_init); static void __exit pcal6416a_exit(void) { i2c_del_driver(&pcal6416a_driver); } module_exit(pcal6416a_exit); MODULE_DESCRIPTION("GPIO expander driver for PCAL6416A"); MODULE_LICENSE("GPL");