Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * common keywest i2c layer
0004  *
0005  * Copyright (c) by Takashi Iwai <tiwai@suse.de>
0006  */
0007 
0008 
0009 #include <linux/init.h>
0010 #include <linux/i2c.h>
0011 #include <linux/delay.h>
0012 #include <linux/module.h>
0013 #include <sound/core.h>
0014 #include "pmac.h"
0015 
0016 static struct pmac_keywest *keywest_ctx;
0017 static bool keywest_probed;
0018 
0019 static int keywest_probe(struct i2c_client *client,
0020              const struct i2c_device_id *id)
0021 {
0022     keywest_probed = true;
0023     /* If instantiated via i2c-powermac, we still need to set the client */
0024     if (!keywest_ctx->client)
0025         keywest_ctx->client = client;
0026     i2c_set_clientdata(client, keywest_ctx);
0027     return 0;
0028 }
0029 
0030 /*
0031  * This is kind of a hack, best would be to turn powermac to fixed i2c
0032  * bus numbers and declare the sound device as part of platform
0033  * initialization
0034  */
0035 static int keywest_attach_adapter(struct i2c_adapter *adapter)
0036 {
0037     struct i2c_board_info info;
0038     struct i2c_client *client;
0039 
0040     if (! keywest_ctx)
0041         return -EINVAL;
0042 
0043     if (strncmp(adapter->name, "mac-io", 6))
0044         return -EINVAL; /* ignored */
0045 
0046     memset(&info, 0, sizeof(struct i2c_board_info));
0047     strscpy(info.type, "keywest", I2C_NAME_SIZE);
0048     info.addr = keywest_ctx->addr;
0049     client = i2c_new_client_device(adapter, &info);
0050     if (IS_ERR(client))
0051         return PTR_ERR(client);
0052     keywest_ctx->client = client;
0053 
0054     /*
0055      * We know the driver is already loaded, so the device should be
0056      * already bound. If not it means binding failed, and then there
0057      * is no point in keeping the device instantiated.
0058      */
0059     if (!keywest_ctx->client->dev.driver) {
0060         i2c_unregister_device(keywest_ctx->client);
0061         keywest_ctx->client = NULL;
0062         return -ENODEV;
0063     }
0064     
0065     /*
0066      * Let i2c-core delete that device on driver removal.
0067      * This is safe because i2c-core holds the core_lock mutex for us.
0068      */
0069     list_add_tail(&keywest_ctx->client->detected,
0070               &to_i2c_driver(keywest_ctx->client->dev.driver)->clients);
0071     return 0;
0072 }
0073 
0074 static int keywest_remove(struct i2c_client *client)
0075 {
0076     if (! keywest_ctx)
0077         return 0;
0078     if (client == keywest_ctx->client)
0079         keywest_ctx->client = NULL;
0080 
0081     return 0;
0082 }
0083 
0084 
0085 static const struct i2c_device_id keywest_i2c_id[] = {
0086     { "MAC,tas3004", 0 },       /* instantiated by i2c-powermac */
0087     { "keywest", 0 },       /* instantiated by us if needed */
0088     { }
0089 };
0090 MODULE_DEVICE_TABLE(i2c, keywest_i2c_id);
0091 
0092 static struct i2c_driver keywest_driver = {
0093     .driver = {
0094         .name = "PMac Keywest Audio",
0095     },
0096     .probe = keywest_probe,
0097     .remove = keywest_remove,
0098     .id_table = keywest_i2c_id,
0099 };
0100 
0101 /* exported */
0102 void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c)
0103 {
0104     if (keywest_ctx && keywest_ctx == i2c) {
0105         i2c_del_driver(&keywest_driver);
0106         keywest_ctx = NULL;
0107     }
0108 }
0109 
0110 int snd_pmac_tumbler_post_init(void)
0111 {
0112     int err;
0113     
0114     if (!keywest_ctx || !keywest_ctx->client)
0115         return -ENXIO;
0116 
0117     err = keywest_ctx->init_client(keywest_ctx);
0118     if (err < 0) {
0119         snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err);
0120         return err;
0121     }
0122     return 0;
0123 }
0124 
0125 /* exported */
0126 int snd_pmac_keywest_init(struct pmac_keywest *i2c)
0127 {
0128     struct i2c_adapter *adap;
0129     int err, i = 0;
0130 
0131     if (keywest_ctx)
0132         return -EBUSY;
0133 
0134     adap = i2c_get_adapter(0);
0135     if (!adap)
0136         return -EPROBE_DEFER;
0137 
0138     keywest_ctx = i2c;
0139 
0140     err = i2c_add_driver(&keywest_driver);
0141     if (err) {
0142         snd_printk(KERN_ERR "cannot register keywest i2c driver\n");
0143         i2c_put_adapter(adap);
0144         return err;
0145     }
0146 
0147     /* There was already a device from i2c-powermac. Great, let's return */
0148     if (keywest_probed)
0149         return 0;
0150 
0151     /* We assume Macs have consecutive I2C bus numbers starting at 0 */
0152     while (adap) {
0153         /* Scan for devices to be bound to */
0154         err = keywest_attach_adapter(adap);
0155         if (!err)
0156             return 0;
0157         i2c_put_adapter(adap);
0158         adap = i2c_get_adapter(++i);
0159     }
0160 
0161     return -ENODEV;
0162 }