190ee26fbSBingbu Cao // SPDX-License-Identifier: GPL-2.0
290ee26fbSBingbu Cao // Copyright (C) 2018 Intel Corporation
390ee26fbSBingbu Cao
490ee26fbSBingbu Cao #include <linux/acpi.h>
590ee26fbSBingbu Cao #include <linux/delay.h>
690ee26fbSBingbu Cao #include <linux/i2c.h>
790ee26fbSBingbu Cao #include <linux/module.h>
890ee26fbSBingbu Cao #include <linux/pm_runtime.h>
990f7e76eSYassine Oudjana #include <linux/regulator/consumer.h>
1090ee26fbSBingbu Cao #include <media/v4l2-ctrls.h>
1190ee26fbSBingbu Cao #include <media/v4l2-device.h>
1290ee26fbSBingbu Cao
134e671eb5SVincent Knecht struct ak73xx_chipdef {
144e671eb5SVincent Knecht u8 reg_position;
154e671eb5SVincent Knecht u8 reg_cont;
164e671eb5SVincent Knecht u8 shift_pos;
174e671eb5SVincent Knecht u8 mode_active;
184e671eb5SVincent Knecht u8 mode_standby;
19*df15385eSVincent Knecht bool has_standby; /* Some chips may not have standby mode */
204e671eb5SVincent Knecht u16 focus_pos_max;
2190ee26fbSBingbu Cao /*
2290ee26fbSBingbu Cao * This sets the minimum granularity for the focus positions.
2390ee26fbSBingbu Cao * A value of 1 gives maximum accuracy for a desired focus position
2490ee26fbSBingbu Cao */
254e671eb5SVincent Knecht u16 focus_steps;
2690ee26fbSBingbu Cao /*
2790ee26fbSBingbu Cao * This acts as the minimum granularity of lens movement.
2890ee26fbSBingbu Cao * Keep this value power of 2, so the control steps can be
2990ee26fbSBingbu Cao * uniformly adjusted for gradual lens movement, with desired
3090ee26fbSBingbu Cao * number of control steps.
3190ee26fbSBingbu Cao */
324e671eb5SVincent Knecht u16 ctrl_steps;
334e671eb5SVincent Knecht u16 ctrl_delay_us;
3490f7e76eSYassine Oudjana /*
354e671eb5SVincent Knecht * The vcm may take time (tDELAY) to power on and start taking
364e671eb5SVincent Knecht * I2C messages.
3790f7e76eSYassine Oudjana */
384e671eb5SVincent Knecht u16 power_delay_us;
394e671eb5SVincent Knecht };
4090ee26fbSBingbu Cao
41*df15385eSVincent Knecht static const struct ak73xx_chipdef ak7345_cdef = {
42*df15385eSVincent Knecht .reg_position = 0x0,
43*df15385eSVincent Knecht .reg_cont = 0x2,
44*df15385eSVincent Knecht .shift_pos = 7, /* 9 bits position values, need to << 7 */
45*df15385eSVincent Knecht .mode_active = 0x0,
46*df15385eSVincent Knecht .has_standby = false,
47*df15385eSVincent Knecht .focus_pos_max = 511,
48*df15385eSVincent Knecht .focus_steps = 1,
49*df15385eSVincent Knecht .ctrl_steps = 16,
50*df15385eSVincent Knecht .ctrl_delay_us = 1000,
51*df15385eSVincent Knecht .power_delay_us = 20000,
52*df15385eSVincent Knecht };
53*df15385eSVincent Knecht
544e671eb5SVincent Knecht static const struct ak73xx_chipdef ak7375_cdef = {
554e671eb5SVincent Knecht .reg_position = 0x0,
564e671eb5SVincent Knecht .reg_cont = 0x2,
574e671eb5SVincent Knecht .shift_pos = 4, /* 12 bits position values, need to << 4 */
584e671eb5SVincent Knecht .mode_active = 0x0,
594e671eb5SVincent Knecht .mode_standby = 0x40,
60*df15385eSVincent Knecht .has_standby = true,
614e671eb5SVincent Knecht .focus_pos_max = 4095,
624e671eb5SVincent Knecht .focus_steps = 1,
634e671eb5SVincent Knecht .ctrl_steps = 64,
644e671eb5SVincent Knecht .ctrl_delay_us = 1000,
654e671eb5SVincent Knecht .power_delay_us = 10000,
664e671eb5SVincent Knecht };
6790ee26fbSBingbu Cao
6890f7e76eSYassine Oudjana static const char * const ak7375_supply_names[] = {
6990f7e76eSYassine Oudjana "vdd",
7090f7e76eSYassine Oudjana "vio",
7190f7e76eSYassine Oudjana };
7290f7e76eSYassine Oudjana
7390ee26fbSBingbu Cao /* ak7375 device structure */
7490ee26fbSBingbu Cao struct ak7375_device {
754e671eb5SVincent Knecht const struct ak73xx_chipdef *cdef;
7690ee26fbSBingbu Cao struct v4l2_ctrl_handler ctrls_vcm;
7790ee26fbSBingbu Cao struct v4l2_subdev sd;
7890ee26fbSBingbu Cao struct v4l2_ctrl *focus;
7990f7e76eSYassine Oudjana struct regulator_bulk_data supplies[ARRAY_SIZE(ak7375_supply_names)];
8090f7e76eSYassine Oudjana
8190ee26fbSBingbu Cao /* active or standby mode */
8290ee26fbSBingbu Cao bool active;
8390ee26fbSBingbu Cao };
8490ee26fbSBingbu Cao
to_ak7375_vcm(struct v4l2_ctrl * ctrl)8590ee26fbSBingbu Cao static inline struct ak7375_device *to_ak7375_vcm(struct v4l2_ctrl *ctrl)
8690ee26fbSBingbu Cao {
8790ee26fbSBingbu Cao return container_of(ctrl->handler, struct ak7375_device, ctrls_vcm);
8890ee26fbSBingbu Cao }
8990ee26fbSBingbu Cao
sd_to_ak7375_vcm(struct v4l2_subdev * subdev)9090ee26fbSBingbu Cao static inline struct ak7375_device *sd_to_ak7375_vcm(struct v4l2_subdev *subdev)
9190ee26fbSBingbu Cao {
9290ee26fbSBingbu Cao return container_of(subdev, struct ak7375_device, sd);
9390ee26fbSBingbu Cao }
9490ee26fbSBingbu Cao
ak7375_i2c_write(struct ak7375_device * ak7375,u8 addr,u16 data,u8 size)9590ee26fbSBingbu Cao static int ak7375_i2c_write(struct ak7375_device *ak7375,
9690ee26fbSBingbu Cao u8 addr, u16 data, u8 size)
9790ee26fbSBingbu Cao {
9890ee26fbSBingbu Cao struct i2c_client *client = v4l2_get_subdevdata(&ak7375->sd);
9990ee26fbSBingbu Cao u8 buf[3];
10090ee26fbSBingbu Cao int ret;
10190ee26fbSBingbu Cao
10290ee26fbSBingbu Cao if (size != 1 && size != 2)
10390ee26fbSBingbu Cao return -EINVAL;
10490ee26fbSBingbu Cao buf[0] = addr;
10590ee26fbSBingbu Cao buf[size] = data & 0xff;
10690ee26fbSBingbu Cao if (size == 2)
10790ee26fbSBingbu Cao buf[1] = (data >> 8) & 0xff;
10890ee26fbSBingbu Cao ret = i2c_master_send(client, (const char *)buf, size + 1);
10990ee26fbSBingbu Cao if (ret < 0)
11090ee26fbSBingbu Cao return ret;
11190ee26fbSBingbu Cao if (ret != size + 1)
11290ee26fbSBingbu Cao return -EIO;
11390ee26fbSBingbu Cao
11490ee26fbSBingbu Cao return 0;
11590ee26fbSBingbu Cao }
11690ee26fbSBingbu Cao
ak7375_set_ctrl(struct v4l2_ctrl * ctrl)11790ee26fbSBingbu Cao static int ak7375_set_ctrl(struct v4l2_ctrl *ctrl)
11890ee26fbSBingbu Cao {
11990ee26fbSBingbu Cao struct ak7375_device *dev_vcm = to_ak7375_vcm(ctrl);
1204e671eb5SVincent Knecht const struct ak73xx_chipdef *cdef = dev_vcm->cdef;
12190ee26fbSBingbu Cao
12290ee26fbSBingbu Cao if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE)
1234e671eb5SVincent Knecht return ak7375_i2c_write(dev_vcm, cdef->reg_position,
1244e671eb5SVincent Knecht ctrl->val << cdef->shift_pos, 2);
12590ee26fbSBingbu Cao
12690ee26fbSBingbu Cao return -EINVAL;
12790ee26fbSBingbu Cao }
12890ee26fbSBingbu Cao
12990ee26fbSBingbu Cao static const struct v4l2_ctrl_ops ak7375_vcm_ctrl_ops = {
13090ee26fbSBingbu Cao .s_ctrl = ak7375_set_ctrl,
13190ee26fbSBingbu Cao };
13290ee26fbSBingbu Cao
ak7375_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)13390ee26fbSBingbu Cao static int ak7375_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
13490ee26fbSBingbu Cao {
135401b0e5dSMauro Carvalho Chehab return pm_runtime_resume_and_get(sd->dev);
13690ee26fbSBingbu Cao }
13790ee26fbSBingbu Cao
ak7375_close(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)13890ee26fbSBingbu Cao static int ak7375_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
13990ee26fbSBingbu Cao {
14090ee26fbSBingbu Cao pm_runtime_put(sd->dev);
14190ee26fbSBingbu Cao
14290ee26fbSBingbu Cao return 0;
14390ee26fbSBingbu Cao }
14490ee26fbSBingbu Cao
14590ee26fbSBingbu Cao static const struct v4l2_subdev_internal_ops ak7375_int_ops = {
14690ee26fbSBingbu Cao .open = ak7375_open,
14790ee26fbSBingbu Cao .close = ak7375_close,
14890ee26fbSBingbu Cao };
14990ee26fbSBingbu Cao
15090ee26fbSBingbu Cao static const struct v4l2_subdev_ops ak7375_ops = { };
15190ee26fbSBingbu Cao
ak7375_subdev_cleanup(struct ak7375_device * ak7375_dev)15290ee26fbSBingbu Cao static void ak7375_subdev_cleanup(struct ak7375_device *ak7375_dev)
15390ee26fbSBingbu Cao {
15490ee26fbSBingbu Cao v4l2_async_unregister_subdev(&ak7375_dev->sd);
15590ee26fbSBingbu Cao v4l2_ctrl_handler_free(&ak7375_dev->ctrls_vcm);
15690ee26fbSBingbu Cao media_entity_cleanup(&ak7375_dev->sd.entity);
15790ee26fbSBingbu Cao }
15890ee26fbSBingbu Cao
ak7375_init_controls(struct ak7375_device * dev_vcm)15990ee26fbSBingbu Cao static int ak7375_init_controls(struct ak7375_device *dev_vcm)
16090ee26fbSBingbu Cao {
16190ee26fbSBingbu Cao struct v4l2_ctrl_handler *hdl = &dev_vcm->ctrls_vcm;
16290ee26fbSBingbu Cao const struct v4l2_ctrl_ops *ops = &ak7375_vcm_ctrl_ops;
1634e671eb5SVincent Knecht const struct ak73xx_chipdef *cdef = dev_vcm->cdef;
16490ee26fbSBingbu Cao
16590ee26fbSBingbu Cao v4l2_ctrl_handler_init(hdl, 1);
16690ee26fbSBingbu Cao
16790ee26fbSBingbu Cao dev_vcm->focus = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE,
1684e671eb5SVincent Knecht 0, cdef->focus_pos_max, cdef->focus_steps, 0);
16990ee26fbSBingbu Cao
17090ee26fbSBingbu Cao if (hdl->error)
17190ee26fbSBingbu Cao dev_err(dev_vcm->sd.dev, "%s fail error: 0x%x\n",
17290ee26fbSBingbu Cao __func__, hdl->error);
17390ee26fbSBingbu Cao dev_vcm->sd.ctrl_handler = hdl;
17490ee26fbSBingbu Cao
17590ee26fbSBingbu Cao return hdl->error;
17690ee26fbSBingbu Cao }
17790ee26fbSBingbu Cao
ak7375_probe(struct i2c_client * client)17890ee26fbSBingbu Cao static int ak7375_probe(struct i2c_client *client)
17990ee26fbSBingbu Cao {
18090ee26fbSBingbu Cao struct ak7375_device *ak7375_dev;
18190ee26fbSBingbu Cao int ret;
18290f7e76eSYassine Oudjana unsigned int i;
18390ee26fbSBingbu Cao
18490ee26fbSBingbu Cao ak7375_dev = devm_kzalloc(&client->dev, sizeof(*ak7375_dev),
18590ee26fbSBingbu Cao GFP_KERNEL);
18690ee26fbSBingbu Cao if (!ak7375_dev)
18790ee26fbSBingbu Cao return -ENOMEM;
18890ee26fbSBingbu Cao
1894e671eb5SVincent Knecht ak7375_dev->cdef = device_get_match_data(&client->dev);
1904e671eb5SVincent Knecht
19190f7e76eSYassine Oudjana for (i = 0; i < ARRAY_SIZE(ak7375_supply_names); i++)
19290f7e76eSYassine Oudjana ak7375_dev->supplies[i].supply = ak7375_supply_names[i];
19390f7e76eSYassine Oudjana
19490f7e76eSYassine Oudjana ret = devm_regulator_bulk_get(&client->dev,
19590f7e76eSYassine Oudjana ARRAY_SIZE(ak7375_supply_names),
19690f7e76eSYassine Oudjana ak7375_dev->supplies);
19790f7e76eSYassine Oudjana if (ret) {
19890f7e76eSYassine Oudjana dev_err_probe(&client->dev, ret, "Failed to get regulators\n");
19990f7e76eSYassine Oudjana return ret;
20090f7e76eSYassine Oudjana }
20190f7e76eSYassine Oudjana
20290ee26fbSBingbu Cao v4l2_i2c_subdev_init(&ak7375_dev->sd, client, &ak7375_ops);
20390ee26fbSBingbu Cao ak7375_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
20490ee26fbSBingbu Cao ak7375_dev->sd.internal_ops = &ak7375_int_ops;
20590ee26fbSBingbu Cao ak7375_dev->sd.entity.function = MEDIA_ENT_F_LENS;
20690ee26fbSBingbu Cao
20790ee26fbSBingbu Cao ret = ak7375_init_controls(ak7375_dev);
20890ee26fbSBingbu Cao if (ret)
20990ee26fbSBingbu Cao goto err_cleanup;
21090ee26fbSBingbu Cao
21190ee26fbSBingbu Cao ret = media_entity_pads_init(&ak7375_dev->sd.entity, 0, NULL);
21290ee26fbSBingbu Cao if (ret < 0)
21390ee26fbSBingbu Cao goto err_cleanup;
21490ee26fbSBingbu Cao
21590ee26fbSBingbu Cao ret = v4l2_async_register_subdev(&ak7375_dev->sd);
21690ee26fbSBingbu Cao if (ret < 0)
21790ee26fbSBingbu Cao goto err_cleanup;
21890ee26fbSBingbu Cao
21990ee26fbSBingbu Cao pm_runtime_set_active(&client->dev);
22090ee26fbSBingbu Cao pm_runtime_enable(&client->dev);
22190ee26fbSBingbu Cao pm_runtime_idle(&client->dev);
22290ee26fbSBingbu Cao
22390ee26fbSBingbu Cao return 0;
22490ee26fbSBingbu Cao
22590ee26fbSBingbu Cao err_cleanup:
22690ee26fbSBingbu Cao v4l2_ctrl_handler_free(&ak7375_dev->ctrls_vcm);
22790ee26fbSBingbu Cao media_entity_cleanup(&ak7375_dev->sd.entity);
22890ee26fbSBingbu Cao
22990ee26fbSBingbu Cao return ret;
23090ee26fbSBingbu Cao }
23190ee26fbSBingbu Cao
ak7375_remove(struct i2c_client * client)232ed5c2f5fSUwe Kleine-König static void ak7375_remove(struct i2c_client *client)
23390ee26fbSBingbu Cao {
23490ee26fbSBingbu Cao struct v4l2_subdev *sd = i2c_get_clientdata(client);
23590ee26fbSBingbu Cao struct ak7375_device *ak7375_dev = sd_to_ak7375_vcm(sd);
23690ee26fbSBingbu Cao
23790ee26fbSBingbu Cao ak7375_subdev_cleanup(ak7375_dev);
23890ee26fbSBingbu Cao pm_runtime_disable(&client->dev);
23990ee26fbSBingbu Cao pm_runtime_set_suspended(&client->dev);
24090ee26fbSBingbu Cao }
24190ee26fbSBingbu Cao
24290ee26fbSBingbu Cao /*
24390ee26fbSBingbu Cao * This function sets the vcm position, so it consumes least current
2444e671eb5SVincent Knecht * The lens position is gradually moved in units of ctrl_steps,
24590ee26fbSBingbu Cao * to make the movements smoothly.
24690ee26fbSBingbu Cao */
ak7375_vcm_suspend(struct device * dev)24790ee26fbSBingbu Cao static int __maybe_unused ak7375_vcm_suspend(struct device *dev)
24890ee26fbSBingbu Cao {
249334abb57SKrzysztof Kozlowski struct v4l2_subdev *sd = dev_get_drvdata(dev);
25090ee26fbSBingbu Cao struct ak7375_device *ak7375_dev = sd_to_ak7375_vcm(sd);
2514e671eb5SVincent Knecht const struct ak73xx_chipdef *cdef = ak7375_dev->cdef;
25290ee26fbSBingbu Cao int ret, val;
25390ee26fbSBingbu Cao
25490ee26fbSBingbu Cao if (!ak7375_dev->active)
25590ee26fbSBingbu Cao return 0;
25690ee26fbSBingbu Cao
2574e671eb5SVincent Knecht for (val = ak7375_dev->focus->val & ~(cdef->ctrl_steps - 1);
2584e671eb5SVincent Knecht val >= 0; val -= cdef->ctrl_steps) {
2594e671eb5SVincent Knecht ret = ak7375_i2c_write(ak7375_dev, cdef->reg_position,
2604e671eb5SVincent Knecht val << cdef->shift_pos, 2);
26190ee26fbSBingbu Cao if (ret)
26290ee26fbSBingbu Cao dev_err_once(dev, "%s I2C failure: %d\n",
26390ee26fbSBingbu Cao __func__, ret);
2644e671eb5SVincent Knecht usleep_range(cdef->ctrl_delay_us, cdef->ctrl_delay_us + 10);
26590ee26fbSBingbu Cao }
26690ee26fbSBingbu Cao
267*df15385eSVincent Knecht if (cdef->has_standby) {
2684e671eb5SVincent Knecht ret = ak7375_i2c_write(ak7375_dev, cdef->reg_cont,
2694e671eb5SVincent Knecht cdef->mode_standby, 1);
27090ee26fbSBingbu Cao if (ret)
27190ee26fbSBingbu Cao dev_err(dev, "%s I2C failure: %d\n", __func__, ret);
272*df15385eSVincent Knecht }
27390ee26fbSBingbu Cao
27490f7e76eSYassine Oudjana ret = regulator_bulk_disable(ARRAY_SIZE(ak7375_supply_names),
27590f7e76eSYassine Oudjana ak7375_dev->supplies);
27690f7e76eSYassine Oudjana if (ret)
27790f7e76eSYassine Oudjana return ret;
27890f7e76eSYassine Oudjana
27990ee26fbSBingbu Cao ak7375_dev->active = false;
28090ee26fbSBingbu Cao
28190ee26fbSBingbu Cao return 0;
28290ee26fbSBingbu Cao }
28390ee26fbSBingbu Cao
28490ee26fbSBingbu Cao /*
28590ee26fbSBingbu Cao * This function sets the vcm position to the value set by the user
28690ee26fbSBingbu Cao * through v4l2_ctrl_ops s_ctrl handler
2874e671eb5SVincent Knecht * The lens position is gradually moved in units of ctrl_steps,
28890ee26fbSBingbu Cao * to make the movements smoothly.
28990ee26fbSBingbu Cao */
ak7375_vcm_resume(struct device * dev)29090ee26fbSBingbu Cao static int __maybe_unused ak7375_vcm_resume(struct device *dev)
29190ee26fbSBingbu Cao {
292334abb57SKrzysztof Kozlowski struct v4l2_subdev *sd = dev_get_drvdata(dev);
29390ee26fbSBingbu Cao struct ak7375_device *ak7375_dev = sd_to_ak7375_vcm(sd);
2944e671eb5SVincent Knecht const struct ak73xx_chipdef *cdef = ak7375_dev->cdef;
29590ee26fbSBingbu Cao int ret, val;
29690ee26fbSBingbu Cao
29790ee26fbSBingbu Cao if (ak7375_dev->active)
29890ee26fbSBingbu Cao return 0;
29990ee26fbSBingbu Cao
30090f7e76eSYassine Oudjana ret = regulator_bulk_enable(ARRAY_SIZE(ak7375_supply_names),
30190f7e76eSYassine Oudjana ak7375_dev->supplies);
30290f7e76eSYassine Oudjana if (ret)
30390f7e76eSYassine Oudjana return ret;
30490f7e76eSYassine Oudjana
30590f7e76eSYassine Oudjana /* Wait for vcm to become ready */
3064e671eb5SVincent Knecht usleep_range(cdef->power_delay_us, cdef->power_delay_us + 500);
30790f7e76eSYassine Oudjana
3084e671eb5SVincent Knecht ret = ak7375_i2c_write(ak7375_dev, cdef->reg_cont,
3094e671eb5SVincent Knecht cdef->mode_active, 1);
31090ee26fbSBingbu Cao if (ret) {
31190ee26fbSBingbu Cao dev_err(dev, "%s I2C failure: %d\n", __func__, ret);
31290ee26fbSBingbu Cao return ret;
31390ee26fbSBingbu Cao }
31490ee26fbSBingbu Cao
3154e671eb5SVincent Knecht for (val = ak7375_dev->focus->val % cdef->ctrl_steps;
31690ee26fbSBingbu Cao val <= ak7375_dev->focus->val;
3174e671eb5SVincent Knecht val += cdef->ctrl_steps) {
3184e671eb5SVincent Knecht ret = ak7375_i2c_write(ak7375_dev, cdef->reg_position,
3194e671eb5SVincent Knecht val << cdef->shift_pos, 2);
32090ee26fbSBingbu Cao if (ret)
32190ee26fbSBingbu Cao dev_err_ratelimited(dev, "%s I2C failure: %d\n",
32290ee26fbSBingbu Cao __func__, ret);
3234e671eb5SVincent Knecht usleep_range(cdef->ctrl_delay_us, cdef->ctrl_delay_us + 10);
32490ee26fbSBingbu Cao }
32590ee26fbSBingbu Cao
32690ee26fbSBingbu Cao ak7375_dev->active = true;
32790ee26fbSBingbu Cao
32890ee26fbSBingbu Cao return 0;
32990ee26fbSBingbu Cao }
33090ee26fbSBingbu Cao
33190ee26fbSBingbu Cao static const struct of_device_id ak7375_of_table[] = {
332*df15385eSVincent Knecht { .compatible = "asahi-kasei,ak7345", .data = &ak7345_cdef, },
3334e671eb5SVincent Knecht { .compatible = "asahi-kasei,ak7375", .data = &ak7375_cdef, },
33490ee26fbSBingbu Cao { /* sentinel */ }
33590ee26fbSBingbu Cao };
33690ee26fbSBingbu Cao MODULE_DEVICE_TABLE(of, ak7375_of_table);
33790ee26fbSBingbu Cao
33890ee26fbSBingbu Cao static const struct dev_pm_ops ak7375_pm_ops = {
33990ee26fbSBingbu Cao SET_SYSTEM_SLEEP_PM_OPS(ak7375_vcm_suspend, ak7375_vcm_resume)
34090ee26fbSBingbu Cao SET_RUNTIME_PM_OPS(ak7375_vcm_suspend, ak7375_vcm_resume, NULL)
34190ee26fbSBingbu Cao };
34290ee26fbSBingbu Cao
34390ee26fbSBingbu Cao static struct i2c_driver ak7375_i2c_driver = {
34490ee26fbSBingbu Cao .driver = {
34590ee26fbSBingbu Cao .name = "ak7375",
34690ee26fbSBingbu Cao .pm = &ak7375_pm_ops,
34790ee26fbSBingbu Cao .of_match_table = ak7375_of_table,
34890ee26fbSBingbu Cao },
349aaeb31c0SUwe Kleine-König .probe = ak7375_probe,
35090ee26fbSBingbu Cao .remove = ak7375_remove,
35190ee26fbSBingbu Cao };
35290ee26fbSBingbu Cao module_i2c_driver(ak7375_i2c_driver);
35390ee26fbSBingbu Cao
35490ee26fbSBingbu Cao MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
35590ee26fbSBingbu Cao MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
35690ee26fbSBingbu Cao MODULE_DESCRIPTION("AK7375 VCM driver");
35790ee26fbSBingbu Cao MODULE_LICENSE("GPL v2");
358