static int __devinit twl6040_codec_probe(struct platform_device *pdev) { struct twl4030_codec_data *pdata = pdev->dev.platform_data; struct twl6040_codec *twl6040; struct mfd_cell *cell = NULL; unsigned int naudint; int audpwron; int ret, children = 0; u8 icrev = 0, accctl; if(!pdata) { dev_err(&pdev->dev, "Platform data is missing\n"); return -EINVAL; } twl6040 = kzalloc(sizeof(struct twl6040_codec), GFP_KERNEL); if (!twl6040) return -ENOMEM; platform_set_drvdata(pdev, twl6040); twl6040_codec_dev = pdev; twl6040->dev = &pdev->dev; mutex_init(&twl6040->mutex); mutex_init(&twl6040->io_mutex); icrev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); if (pdata && (icrev > 0)) audpwron = pdata->audpwron_gpio; else audpwron = -EINVAL; if (pdata) naudint = pdata->naudint_irq; else naudint = 0; twl6040->audpwron = audpwron; twl6040->powered = 0; twl6040->irq = naudint; twl6040->irq_base = pdata->irq_base; init_completion(&twl6040->ready); if (gpio_is_valid(audpwron)) { ret = gpio_request(audpwron, "audpwron"); if (ret) goto gpio1_err; ret = gpio_direction_output(audpwron, 0); if (ret) goto gpio2_err; } if (naudint) { /* codec interrupt */ ret = twl6040_irq_init(twl6040); if (ret) goto gpio2_err; ret = twl6040_request_irq(twl6040, TWL6040_IRQ_READY, twl6040_naudint_handler, "twl6040_irq_ready", twl6040); if (ret) { dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret); goto irq_err; } } /* dual-access registers controlled by I2C only */ accctl = twl6040_reg_read(twl6040, TWL6040_REG_ACCCTL); twl6040_reg_write(twl6040, TWL6040_REG_ACCCTL, accctl | TWL6040_I2CSEL); if (pdata->audio) { cell = &twl6040->cells[children]; cell->name = "twl6040-codec"; cell->platform_data = pdata->audio; cell->data_size = sizeof(*pdata->audio); children++; } if (pdata->vibra) { cell = &twl6040->cells[children]; cell->name = "vib-twl6040"; cell->platform_data = pdata->vibra; cell->data_size = sizeof(*pdata->vibra); children++; } if (children) { ret = mfd_add_devices(&pdev->dev, pdev->id, twl6040->cells, children, NULL, 0); if (ret) goto mfd_err; } else { dev_err(&pdev->dev, "No platform data found for children\n"); ret = -ENODEV; goto mfd_err; } return 0; mfd_err: if (naudint) twl6040_free_irq(twl6040, TWL6040_IRQ_READY, twl6040); irq_err: if (naudint) twl6040_irq_exit(twl6040); gpio2_err: if (gpio_is_valid(audpwron)) gpio_free(audpwron); gpio1_err: platform_set_drvdata(pdev, NULL); kfree(twl6040); twl6040_codec_dev = NULL; return ret; }
static int __devinit twl6040_probe(struct platform_device *pdev) { struct twl4030_audio_data *pdata = pdev->dev.platform_data; struct twl6040 *twl6040; struct mfd_cell *cell = NULL; int ret, children = 0; if (!pdata) { dev_err(&pdev->dev, "Platform data is missing\n"); return -EINVAL; } /* In order to operate correctly we need valid interrupt config */ if (!pdata->naudint_irq || !pdata->irq_base) { dev_err(&pdev->dev, "Invalid IRQ configuration\n"); return -EINVAL; } twl6040 = kzalloc(sizeof(struct twl6040), GFP_KERNEL); if (!twl6040) return -ENOMEM; platform_set_drvdata(pdev, twl6040); twl6040_dev = pdev; twl6040->dev = &pdev->dev; twl6040->audpwron = pdata->audpwron_gpio; twl6040->irq = pdata->naudint_irq; twl6040->irq_base = pdata->irq_base; mutex_init(&twl6040->mutex); mutex_init(&twl6040->io_mutex); init_completion(&twl6040->ready); twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); if (gpio_is_valid(twl6040->audpwron)) { ret = gpio_request(twl6040->audpwron, "audpwron"); if (ret) goto gpio1_err; ret = gpio_direction_output(twl6040->audpwron, 0); if (ret) goto gpio2_err; } /* ERRATA: Automatic power-up is not possible in ES1.0 */ if (twl6040->rev == TWL6040_REV_ES1_0) twl6040->audpwron = -EINVAL; /* codec interrupt */ ret = twl6040_irq_init(twl6040); if (ret) goto gpio2_err; ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY, NULL, twl6040_naudint_handler, 0, "twl6040_irq_ready", twl6040); if (ret) { dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret); goto irq_err; } /* dual-access registers controlled by I2C only */ twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_I2CSEL); if (pdata->codec) { int irq = twl6040->irq_base + TWL6040_IRQ_PLUG; cell = &twl6040->cells[children]; cell->name = "twl6040-codec"; twl6040_codec_rsrc[0].start = irq; twl6040_codec_rsrc[0].end = irq; cell->resources = twl6040_codec_rsrc; cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc); cell->platform_data = pdata->codec; cell->pdata_size = sizeof(*pdata->codec); children++; } if (pdata->vibra) { int irq = twl6040->irq_base + TWL6040_IRQ_VIB; cell = &twl6040->cells[children]; cell->name = "twl6040-vibra"; twl6040_vibra_rsrc[0].start = irq; twl6040_vibra_rsrc[0].end = irq; cell->resources = twl6040_vibra_rsrc; cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc); cell->platform_data = pdata->vibra; cell->pdata_size = sizeof(*pdata->vibra); children++; } if (children) { ret = mfd_add_devices(&pdev->dev, pdev->id, twl6040->cells, children, NULL, 0); if (ret) goto mfd_err; } else { dev_err(&pdev->dev, "No platform data found for children\n"); ret = -ENODEV; goto mfd_err; } return 0; mfd_err: free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040); irq_err: twl6040_irq_exit(twl6040); gpio2_err: if (gpio_is_valid(twl6040->audpwron)) gpio_free(twl6040->audpwron); gpio1_err: platform_set_drvdata(pdev, NULL); kfree(twl6040); twl6040_dev = NULL; return ret; }